- - PR -
分割コミットとトランザクションについて
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2007-10-04 11:26
分割コミットについて
大量のデータ(約XX件)をDBに登録する処理の実装を考えています。 処理の概要としては、データを一括に登録するのではなく、 100件ごとに分割でコミットを行い。 登録の際に例外が発生した場合は前回のコミット時点までロールバックを行い、 引き続きデータを登録を行います。 処理イメージ データA 登録 データB 登録 コミット データC 登録 データD 登録 エラー発生 ロールバック データE 登録 データF 登録 コミット 実行後のDBのデータ格納状態 データA データB データE データF このような処理を実装する場合、 気になった点としましては、 このような分割でデータ登録の処理を実装する場合の トランザクションの考え方はどのようになるのか? 初期の考え方では、処理の開始前にトランザクションの開始を行うだけでいいと思いましたが、 サンプルプログラムの実装を進めていくと、コミット、ロールバックを行った後に、 そのたびにトランザクションを開始しなければ、処理イメージのように実装できませんでした。 このような分割でコミットを行う場合は、そのたびにトランザクションの開始を行う 処理イメージで正しいのでしょうか? サンプルプログラムのソースコードは以下のようになっています。 ApplicationContext context = new ClassPathXmlApplicationContext("/config/applicationContext.xml"); PlatformTransactionManager tm = (PlatformTransactionManager) context.getBean("transactionManager"); DefaultTransactionDefinition def = new DefaultTransactionDefinition(); // トランザクションの振る舞いを設定 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = null; // トランザクションの開始 status = tm.getTransaction(def); SampleDto dto = new SampleDto(); SampleDAO dao = (SampleDAO) context.getBean("sampleDao"); dto = createDummyDto("A"); dao.insert(dto); dto = createDummyDto("B"); dao.insert(dto); // *** コミットを行う *** tm.commit(status); // トランザクションの開始 status = tm.getTransaction(def); dto = createDummyDto("C"); dao.insert(dto); dto = createDummyDto("D"); dao.insert(dto); // *** ロールバックを行う *** tm.rollback(status); // トランザクションの開始 status = tm.getTransaction(def); dto = createDummyDto("E"); dao.insert(dto); dto = createDummyDto("F"); dao.insert(dto); // *** コミットを行う *** tm.commit(status); [環境] OS:Windows XP SP2 Java:JDK1.5.0_12 DB:Oracle 10g O/R:IBatis 2.3 FrameWork:Spring 2.0 Transaction Manager:PlatformTransactionManager(Spring提供クラス) | ||||
|
投稿日時: 2007-10-04 11:56
トランザクションの境界は、開始から終了までです。
100件分の処理単位を1メソッドとし、 トランザクションをPROPAGATION_REQUIRES_NEWにすれば、 メソッドの呼び出し単位で新しいトランザクションになったと思います。 PROPAGATION_REQUIREDならトランザクションが開始されていれば、 そのままそのトランザクションに参加するので、制御が面倒になりますよ。 | ||||
|
投稿日時: 2007-10-04 12:30
トランザクションの開始・終了はあくまでも最初の DML 実行から commit/rollback までですから、データの登録を分割したとして「データD 登録 エラー発生」して rollback を投げたとしても、その前の A, B は入ったままですね。
ところで、自動コミットは無効にしているんでしょうか? _________________ もしもし@RMAN 友の会 | ||||
|
投稿日時: 2007-10-04 13:42
明示的に自動コミットをfalseに設定しなければならないような
XAConnection(Connectionをラップするタイプ)の実装って、 殆ど存在しないような気がします。 | ||||
|
投稿日時: 2007-10-04 14:46
もうしわけないです。その辺り詳しくないので、とりあえず JDBC で単純に接続してトランザクション投げて、くらいしか想定してなかったです。orz _________________ もしもし@RMAN 友の会 | ||||
|
投稿日時: 2007-10-04 15:08
JDBC3.0 をサポートするドライバであればセーブポイントが使えるかも?
http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Connection.html#setSavepoint() http://www.devx.com/tips/Tip/17052 | ||||
|
投稿日時: 2007-10-04 15:20
なぜSpringのトランザクション管理機構を使っていながら
自力でcommit/rollbackしようとしているのでしょうか? その辺りの管理はTransactionInterceptorにまかせましょう。 管理用データ等の更新用トランザクションの必要性に応じて PROPAGATION_NOT_SUPPORTED、PROPAGATION_REQUIRES_NEWを指定した メソッドを外側に配置して、 そのメソッドの内側から一回分のトランザクション用のデータを PROPAGATION_REQUIRES_NEWを指定したメソッドに更新を行わせれば、 期待されている動作になると思います。
XAConnectionもGlobal Transactionにenlistされていなければ 普通のConnectionと同様にautoCommitがデフォルトだったと思います。 | ||||
|
投稿日時: 2007-10-04 16:56
>あしゅさん
誤解を招く発言でごめんなさい。 JTAを使う上で意識する必要は殆どないのでは? という意味です。 でも、一部の実装では明示的に物理コネクションに、 setAutoCommit(false)を実行しなければいけないものがあるみたいですね・・・ |