そんなトランザクションマネージャで大丈夫か?
TRANSCRIPT
たとえば...
● 複数のDBに対する処理● DBに対する処理とJMSによるメッセージ送信
DB DB
プログラム
DB MQ
プログラム
参照・更新メッセージ送信・受信参照・更新 参照・更新
1トランザクションで処理する
2フェーズコミット
● XADataSourceが必要● XADataSourceの実装はJDBCドライバによっ
て提供される● 非XAリソースをラップしてエミュレーションする
機能を持っている場合もある
XAトランザクションのSQL(MySQLの場合)
mysql> XA START 'xatest';Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO account VALUES(1, 'takezoe');Query OK, 1 row affected (0.04 sec)
mysql> XA END 'xatest';Query OK, 0 rows affected (0.00 sec)
mysql> XA PREPARE 'xatest';Query OK, 0 rows affected (0.00 sec)
mysql> XA COMMIT 'xatest';Query OK, 0 rows affected (0.00 sec)
リカバリマネージャ
● トランザクションマネージャはトランザクションの状態をトランザクションログに出力している
● リカバリマネージャはトランザクションログを見て不正なトランザクションを自動的にリカバリする
リカバリマネージャ
トランザクションマネージャ
リカバリマネージャ
トランザクションログ
トランザクションの状態を書き込み
残ってしまっているトランザクションがないか
定期的にチェック
残ってしまっているトランザクションを検出した場合はリカバリを実行
誤検出しないよう、トランザクションマネージャの管理下になく、かつ一定時間ステータスが変わっていないもの、というようなチェックを行っている
トランザクションのリカバリとは?
● リソース側に残っているトランザクションをrollbackまたはcommitのどちらかに倒す
● 基本的には安全サイド(rollback)に倒す● すでに1つでもリソースをcommitしてしまってい
る場合は全部commitする
どこで落ちたかでリカバリ方法が異なる
リソース1 リソース2トランザクションマネージャ
プログラム
commit
prepare?
commit
prepare?
commit
ここで落ちた場合は両方rollbackする
ここで落ちた場合はリソース2をcommitする
手動リカバリ(MySQLの場合)mysql> XA RECOVER;+----------+--------------+--------------+--------+| formatID | gtrid_length | bqual_length | data |+----------+--------------+--------------+--------+| 1 | 6 | 0 | xatest |+----------+--------------+--------------+--------+
1 row in set (0.00 sec)
mysql> XA ROLLBACK 'xatest';Query OK, 0 rows affected (0.00 sec)
mysql> XA RECOVER;Empty set (0.00 sec)
XAトランザクションが残ってしまっている
他のリソースの状態をトランザクションIDで突き合せてcommitするべきかrollbackするべきか判断し、トランザクションをリカバリする
残ってしまっていたXAトランザクションが消えた
Seasar2
● なんちゃってXADataSource<component name="xaDataSource" class="org.seasar.extension.dbcp.impl.XADataSourceImpl"> <property name="driverClassName">"oracle.jdbc.driver.OracleDriver"</property> <property name="URL">"jdbc:oracle:thin:@xxx:1521:yyy"</property> <property name="user">"aaa"</property> <property name="password">"bbb"</property></component>
Seasar2のサンプルなどにはこういった設定例が紹介されているが、これはSeasar2側で用意しているXADataSourceのなんちゃって実装で、通常の java.sql.ConnectionをラップしてXAの動作をエミュレートするもの。
Seasar2● 2フェーズコミットを行うのであればJDBCドライバが提供し
ているXADataSourceの実装を使うべき○ com.mysql.jdbc.jdbc2.optional.MysqlXADataSource○ org.postgresql.xa.PGXADataSource
<component name="xaDataSource" class="org.postgresql.xa.PGXADataSource"> <property name="serverName">"localhost"</property>
<property name="databaseName">"TEST"</property><property name="user">"xxxx"</property><property name="password">"xxxx"</property>
</component>
Spring Framework
● 自前ではJTA対応のトランザクションマネージャの実装は持っていない
● JTA対応のトランザクションマネージャをSpring上で使用するためのアダプタが用意されている
● 2フェーズコミットを使用するにはJavaEEサーバもしくはスタンドアロンのJTA実装と組み合わせて使用する必要がある
まとめ
● 2フェーズコミットを行う場合、手動でのリカバリが必要になるケースが存在するということを意識しておきましょう
● 2フェーズコミットを行う場合はなるべくJavaEEサーバのトランザクションマネージャを使うことをおすすめします
● そもそも2フェーズコミットを行わなくても済むのであればそのほうがよいです
● 分散トランザクションはさらに危険がいっぱいなので近づかないようにしましょうw