トランザクション管理の実現方法
トランザクション管理をもっともシンプルに実現するためには、コマンドパターンを適用することです。すなわち、コミット時の動作とロールバック時の動作をそれぞれコマンドとして登録しておき、コミットもしくはロールバックが実行されたら、登録された該当するコマンドを実行します。
では、簡単なJavaコードから示します。
まず、コマンドパターンの肝となるコマンドの定義からです。Javaのインターフェイスを用いて定義します。
public interface TransactionCommand { public void exec(); }
実際のコマンドは、execメソッドにそれぞれコミット、ロールバック時の動作を記述します。
次に、トランザクションを管理するためのクラスを定義します。
import java.util.ArrayList; import java.util.List; public class Transaction { /** コミット時に実行するコマンド群 */ private Listcommits; /** ロールバック時に実行するコマンド群 */ private List rollbacks; public Transaction(){ // コマンドを管理するリストを生成します。 commits = new ArrayList (); rollbacks = new ArrayList (); } public void addCommitCommand( TransactionCommand cmd ){ // コミット時に実行されるコマンドを登録します。 commits.add(cmd); } public void addRollbackCommand( TransactionCommand cmd ){ // ロールバック時に実行されるコマンドを登録します。 rollbacks.add(cmd); } public void commit(){ // コミットコマンドを実行し、トランザクションを初期化します。 for( TransactionCommand c: commits ) c.exec(); commits.clear(); rollbacks.clear(); } public void rollback(){ // ロールバックコマンドを実行し、トランザクションを初期化します。 for( TransactionCommand c: rollbacks ) c.exec(); commits.clear(); rollbacks.clear(); } }
ポイントは、コミット時に実行されるコマンドと、ロールバック時に実行されるコマンドをそれぞれ保持しておき、コミット・ロールバックが呼ばれたら、それらのコマンドを実行するということです。もちろん、コミット・ロールバックが実行されたら、初期化しておきます。
次に、これらを利用するサンプルコードです。教科書とかにありがちなAcountを用いてみました。
public class Acount { private int acount; private Transaction transaction; public Acount(){ this.acount = 0; this.transaction = new Transaction(); } public void add( final int dacount ){ transaction.addCommitCommand( new TransactionCommand(){ public void exec() { acount += dacount; } } ); } public void sub( final int dacount ){ transaction.addCommitCommand( new TransactionCommand(){ public void exec() { acount -= dacount; } } ); } public void commit(){ transaction.commit(); } public void rollback(){ transaction.rollback(); } public int getAcount(){ return acount; } }
Acountは、add、subをメインのメソッドとしており、add、subが呼ばれると、内部の数値に与えられた数値を加算・減算します。
ここでは、加算減算時に、Transactionを用いることで、トランザクション管理を実現しています。
次に、Acount実行用テストコードです。
public class AcountTest { public static void main( String[] args ){ Acount acount = new Acount(); System.out.print("最初:"); System.out.println(acount.getAcount()); acount.add(20); acount.add(30); acount.add(50); System.out.print("20、30、50を足す:"); System.out.println(acount.getAcount()); acount.commit(); System.out.print("コミットする"); System.out.println(acount.getAcount()); acount.sub(20); acount.sub(30); System.out.print("20、30を引く:"); System.out.println(acount.getAcount()); acount.rollback(); System.out.print("ロールバックする:"); System.out.println(acount.getAcount()); } }
ここでは、Acountに数値を足したり引いたりし、それぞれのときにcommitやrollbackを行って、Acountの数値がどう変化しているかを観察します。
実行すると、次のような結果を得ます。
最初:0 20、30、50を足す:0 コミットする100 20、30を引く:100 ロールバックする:100
結果より、初期状態0のとき、20、30、50を足しただけでは、内部の値は変化せず、コミットして初めて変化していることがわかります。
また、20、30を引いただけでは内部の値は変化せず、さらにロールバックしてもキチンと元の値を維持していることが伺えます。