- PR -

分割コミットとトランザクションについて

投稿者投稿内容
シスアド
会議室デビュー日: 2007/10/02
投稿数: 2
投稿日時: 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提供クラス)
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-10-04 11:56
トランザクションの境界は、開始から終了までです。

100件分の処理単位を1メソッドとし、
トランザクションをPROPAGATION_REQUIRES_NEWにすれば、
メソッドの呼び出し単位で新しいトランザクションになったと思います。

PROPAGATION_REQUIREDならトランザクションが開始されていれば、
そのままそのトランザクションに参加するので、制御が面倒になりますよ。
もしもし
ぬし
会議室デビュー日: 2004/10/15
投稿数: 280
投稿日時: 2007-10-04 12:30
トランザクションの開始・終了はあくまでも最初の DML 実行から commit/rollback までですから、データの登録を分割したとして「データD 登録 エラー発生」して rollback を投げたとしても、その前の A, B は入ったままですね。






ところで、自動コミットは無効にしているんでしょうか?

_________________
もしもし@RMAN 友の会
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-10-04 13:42
明示的に自動コミットをfalseに設定しなければならないような
XAConnection(Connectionをラップするタイプ)の実装って、
殆ど存在しないような気がします。
もしもし
ぬし
会議室デビュー日: 2004/10/15
投稿数: 280
投稿日時: 2007-10-04 14:46
引用:

かつのりさんの書き込み (2007-10-04 13:42) より:
明示的に自動コミットをfalseに設定しなければならないような
XAConnection(Connectionをラップするタイプ)の実装って、
殆ど存在しないような気がします。




もうしわけないです。その辺り詳しくないので、とりあえず JDBC で単純に接続してトランザクション投げて、くらいしか想定してなかったです。orz

_________________
もしもし@RMAN 友の会
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 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
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-10-04 15:20
なぜSpringのトランザクション管理機構を使っていながら
自力でcommit/rollbackしようとしているのでしょうか?
その辺りの管理はTransactionInterceptorにまかせましょう。

管理用データ等の更新用トランザクションの必要性に応じて
PROPAGATION_NOT_SUPPORTED、PROPAGATION_REQUIRES_NEWを指定した
メソッドを外側に配置して、

そのメソッドの内側から一回分のトランザクション用のデータを
PROPAGATION_REQUIRES_NEWを指定したメソッドに更新を行わせれば、
期待されている動作になると思います。

引用:

かつのりさんの書き込み (2007-10-04 13:42) より:
明示的に自動コミットをfalseに設定しなければならないような
XAConnection(Connectionをラップするタイプ)の実装って、
殆ど存在しないような気がします。


XAConnectionもGlobal Transactionにenlistされていなければ
普通のConnectionと同様にautoCommitがデフォルトだったと思います。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-10-04 16:56
>あしゅさん

誤解を招く発言でごめんなさい。
JTAを使う上で意識する必要は殆どないのでは?
という意味です。

でも、一部の実装では明示的に物理コネクションに、
setAutoCommit(false)を実行しなければいけないものがあるみたいですね・・・

スキルアップ/キャリアアップ(JOB@IT)