2016年9月27日火曜日

Springでのトランザクション管理

Springのトランザクション管理は大きく分けて以下の2つの管理方法が存在する。

1.プログラミングによるトランザクション管理

プログラミングによってトランザクションを手動管理する方法。以下のようなイメージでトランザクション制御コードをソースコード内に記述する。
transactionManager.begin();  transactionManager.commit();  transactionManager.rollback();  
ソースコード内にトランザクション制御コードも入りこむため、見通しが悪くなったり制御を間違えるとバグの温床にもなったりするので、極力使うべきではない。

2.宣言的トランザクション管理

「あるメソッドを呼び出したときにトランザクションをかける」と宣言する方法。以下のようなイメージでメソッド(やクラスに)に@Transactionalアノテーションを付与することで実現される。
以下の例では、updateFooメソッドを呼び出したときにトランザクションをかける、ということ。
※XMLベースでも宣言可能だがここではアノテーションベースを利用する
アノテーションベースのイメージ.
public class DefaultFooService implements FooService {            public Foo getFoo(String fooName) {                  // do something          }            // these settings have precedence for this method          @Transactional          public void updateFoo(Foo foo) {                  // do something          }  }  
トランザクション制御コードがソースコード内に入りこむことがないため、この管理方法が推奨されている。
詳細は後述するが、メソッドやクラスに@Transactionalアノテーションを付与することで管理され、トランザクションの開始、コミット、ロールバックは自動で行われる。
ただし、ロールバックの注意点として、非検査例外(RuntimeException及びそのサブクラス)が発生した場合はロールバックされるが、検査例外(Exception及びそのサブクラスでRuntimeExceptionのサブクラスじゃないもの)が発生した場合はロールバックされずコミットされる。
なお、Springの宣言的トランザクションはAOPを使って実現されている。
※AOPについてはSpringでAOPを参照。
本記事では「2.宣言的トランザクション管理」について明記する。

トランザクションマネージャ

Springではいくつかのトランザクションマネージャが用意されている。
これらは利用するDBアクセスAPIによって使い分ける。
DBアクセスAPIトランザクションマネージャ
JDBCorg.springframework.jdbc.datasource.DataSourceTransactionManager
JDOorg.springframework.orm.jdo.JdoTransactionManager
JTAorg.springframework.transaction.jta.JtaTransactionManager
Hibernateorg.springframework.orm.hibernate.HibernateTransactionManager

トランザクション制御

冒頭でも述べたが、以下のようにメソッドにTransactionalアノテーションを付与する方法とクラスにTransactionalアノテーションを付与する方法がある。

メソッドにTransactionalアノテーションを付与する

メソッドにTransactionalアノテーション付与することで、メソッドが呼ばれたタイミング(正確にはメソッド開始前)にトランザクションが開始され、対象のメソッドが正常終了した場合はコミット、例外で終了した場合はロールバックされるようになる(再掲になるがロールバックの注意点として、非検査例外(RuntimeException及びそのサブクラス)が発生した場合はロールバックされるが、検査例外(Exception及びそのサブクラスでRuntimeExceptionのサブクラスじゃないもの)が発生した場合はロールバックされずコミットされる)。いづれもアノテーションを付与しておくだけで自動でやってくれる。
public class DefaultFooService implements FooService {            public Foo getFoo(String fooName) {                  // do something          }            // these settings have precedence for this method          @Transactional          public void updateFoo(Foo foo) {                  // do something          }  }  

クラスにTransactionalアノテーションを付与する

以下のようにクラスにTransactionalアノテーションを付与することで、そのクラス内の全てのメソッドにトランザクション制御をかけることができる。
@Transactional(readOnly = true)  public class DefaultFooService implements FooService {        public Foo getFoo(String fooName) {          // do something      }        // these settings have precedence for this method      @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)      public void updateFoo(Foo foo) {          // do something      }  }  
ただし、クラスに対して記述した設定はメソッドで記述された設定で上書きされることに注意する必要がある。上記の場合、updateFooメソッドは@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)が適用される(クラスに付与されている@Transactional(readOnly = true)は効かない)。
なお、Transactionalアノテーションはpublicメソッドのみに適用可能。public以外のメソッドにも付与できてコンパイルも通るが、実行時エラーにもならないので注意が必要。
you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

Transactionalアノテーションのプロパティと設定例

Transactionalアノテーションに指定可能なプロパティ

プロパティ定義
valueString1つのアプリケーションで複数のトランザクションマネージャを利用する場合に、どのトランザクションマネージャを利用するかを指定する。
propagationEnum: Propagationどのような場合にトランザクションを開始するか等の属性を指定する。
isolationEnum: Isolationトランザクションの分離レベルを指定する。デフォルトはDEFAULTレベル。
readOnlyboolean読み取り専用かどうかを指定する。デフォルトはfalse。
timeoutint (in seconds granularity)そのトランザクションがタイムアウトする時間を指定する(秒指定)。デフォルトは利用しているトランザクション管理システムのタイムアウトを利用する。
rollbackForClass<? extends Throwable>[]検査例外が発生した際もロールバックしたい場合に指定する。
rollbackForClassNameString[]rollbackForと同じ、違いは例外クラス名また例外クラス名の配列を指定するところ。
noRollbackForClass<? extends Throwable>[]ロールバックしたくない場合に指定する。
noRollbackForClassNameString[]noRollbackForと同じ、違いは例外クラス名また例外クラス名の配列を指定するところ。

プロパティの設定例

value

// 利用したいトランザクションマネージャの名前を指定する  @Transactional("order")  

propagation

設定例.
//   常に新しいトランザクションを開始する  @Transactional(propagation=Propagation.REQUIRES_NEW)  
propagationのその他の設定値
プロパティ定義
MANDATORYトランザクションが開始されていなければ例外を発生させる。
NESTEDトランザクションが存在する場合はネストしたトランザクションを開始し、他のPROPAGATION_REQUIREDのように振る舞う。
NEVERトランザクションが開始されていれば例外を発生させる。
NOT_SUPPORTEDトランザクションが存在する場合は中断して、トランザクションをはらない(トランザクションを利用しない)
REQUIREDトランザクションが開始されていなければ新規に開始し、すでに開始されていればそのトランザクションをそのまま利用する。
REQUIRES_NEW常に新しいトランザクションを開始する。トランザクションが存在する場合は中断して新しいトランザクションを開始する。
SUPPORTSトランザクションが開始されていればそれを利用。開始されていなければトランザクションをはらない(トランザクションを利用しない)。

isolation

設定例.
// ダーティーリード・ファジーリードは発生しないが、ファントムリードは発生する可能性がある  @Transactional(isolation=Isolation.REPEATABLE_READ)  
isolationのその他の設定値
※下に行くほど分離レベルが高くなる
プロパティ定義
DEFAULT利用するデータストアのデフォルト分離レベルを利用する。
READ_UNCOMMITTEDダーティーリード・ファジーリード・ファントムリードが発生する可能性がある。
READ_COMMITTEDダーティーリードは発生しないが、ファジーリード・ファントムリードは発生する可能性がある。
REPEATABLE_READダーティーリード・ファジーリードは発生しないが、ファントムリードは発生する可能性がある。
SERIALIZABLEダーティーリード・ファジーリード・ファントムリードは発生する可能性がない。

readOnly

設定例.
// 読み取り専用トランザクション  @Transactional(readOnly = true)  

timeout

設定例.
// 10秒でタイムアウト  @Transactional(timeout = 10)  

rollbackFor

設定例.
//   全ての例外が発生した場合、ロールバックさせる  @Transactional(rollbackFor=Exception.class)  

rollbackForClassName

設定例.
//   全ての例外が発生した場合、ロールバックさせる  @Transactional(rollbackForClassName={"Exception"})  

noRollbackFor

設定例.
//   全ての例外が発生した場合、ロールバックさせないようにする  @Transactional(noRollbackFor=Exception.class)  

noRollbackForClassName

設定例.
//   全ての例外が発生した場合、ロールバックさせないようにする  @Transactional(noRollbackForClassName={"Exception"})  

参考

Windows 10 will soon run Edge in a virtual machine to keep you safe

Microsoft has announced that the next major update to Windows 10 will run its Edge browser in a lightweight virtual machine. Running the update in a virtual machine will make exploiting the browser and attacking the operating system or compromising user data more challenging.

Called Windows Defender Application Guard for Microsoft Edge, the new capability builds on the virtual machine-based security that was first introduced last summer in Windows 10. Windows 10's Virtualization Based Security (VBS) uses small virtual machines and the Hyper-V hypervisor to isolate certain critical data and processes from the rest of the system. The most important of these is Credential Guard, which stores network credentials and password hashes in an isolated virtual machine. This isolation prevents the popular MimiKatz tool from harvesting those password hashes. In turn, it also prevents a hacker from breaking into one machine and then using stolen credentials to spread to other machines on the same network.

The Edge browser already creates a secure sandbox for its processes, a technique that tries to limit the damage that can be done when malicious code runs within the browser. The sandbox has limited access to the rest of the system and its data, so successful exploits need to break free from the sandbox's constraints. Often they do this by attacking the operating system itself, using operating system flaws to elevate their privileges.

Credential Guard's virtual machine is very small and lightweight, running only a relatively simple process to manage credentials. Application Guard will go much further by running large parts of the Edge browser within a virtual machine. This virtual machine won't, however, need a full operating system running inside it?just a minimal set of Windows features required to run the browser. Because Application Guard is running in a virtual machine it will have a much higher barrier between it and the host platform. It can't see other processes, it can't access local storage, it can't access any other installed applications, and, critically, it can't attack the kernel of the host system.

In its first iteration, Application Guard will only be available for Edge. Microsoft won't provide an API or let other applications use it. As with other VBS features, Application Guard will also only be available to users of Windows 10 Enterprise, with administrative control through group policies. Administrators will be able to mark some sites as trusted, and those sites won't use the virtual machine. Admins also be able to control whether untrusted sites can use the clipboard or print.

Microsoft recognizes that this feature would be desirable on consumer machines, too, and not just for Edge. Other browsers such as Chrome would also benefit from this kind of protection. So too would Office's "Protected Mode" that's used for opening documents from untrusted sources.

However, doing this has certain complexities. Currently, virtualized sites can't store persistent cookies, for example, because virtual machines get destroyed when the browser is closed. This may be acceptable for a locked-down enterprise environment, but it isn't a good fit for consumers.

There are also compatibility constraints. VBS installs the Hyper-V hypervisor. This requires a processor with hardware virtualization support, and it also requires I/O virtualization (such as Intel's VT-d) to protect against certain known attacks. This means that some systems in the wild won't support it. There are also software concerns; only one hypervisor can be installed at a time, which means that a machine that's running Hyper-V cannot also run VMware Workstation or Virtual Box, say, or software that uses virtualization behind the scenes, such as the Bluestacks Android-on-Windows software.

This virtualization also likely comes at some performance cost, although Microsoft is not saying just what that performance cost is right now.

Nonetheless, this use of virtualization to harden a system is an exciting move. Experimental and special-use systems such as Qubes OS have used virtualization in a similar way, but are far from mainstream offerings. Microsoft is uniquely positioned take this kind of capability mainstream.

Application Guard will become available later this year in Insider builds of Windows, hitting a stable version some time in 2017.