- PR -

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

投稿者投稿内容
シスアド
会議室デビュー日: 2007/10/02
投稿数: 2
投稿日時: 2007-10-10 12:21
皆様の素早いご意見を下さり、ありがとうございます。
また返信が遅れたことは誠に申し訳ございません。

皆様方のご意見を取り入れ、上記の様な処理を実現をするために、
段階的に処理の実装をしていこうと考え、まずは以下の2つの検証を行っていこうと思います。

1.自動コミット無効の検証
2.設定ファイルによるロールバックの検証

「1.自動コミット無効の検証」についてはapplicationContext.xmlは以下のような設定になっております。
DriverManagerDataSourceのConnectionクラスの設定を行っています。
<!-- JDBC -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>
config/jdbc.properties
</value>
</list>
</property>
</bean>

<!-- DataSource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<property name="connection.autoCommit">
<value>false</value>
</property>
</bean>

「2.設定ファイルによるロールバックの検証」について
あしゅさんのおっしゃった様にApplicationContext.xmlにてトランザクション定義情報の設定を行いました。
1つのトランザクション設定を複数のBeanで共有することができるので設定が楽になると調べてわかりました。
<!-- Attribute Source -->
<bean id="taSource"
class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="commit*">PROPAGATION_REQUIRED,-java.lang.Exception</prop>
<prop key="execute">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

<bean id="traceProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>tInterceptor</value>
</list>
</property>
<property name="beanNames">
<list>
<value>*Service</value>
<value>*Job</value>
</list>
</property>
</bean>

これらの設定を行い、
Mainメソッドから
TransactionJob#execute()を呼び出し、
execute()の内部でTransactionService#registList()を呼び出しています。
registList()の内部でTransactionService#commit()を呼び出しています。

サンプルプログラムのソースコードは以下のようになっています。
ソースコードをそのまま貼り付けた場合膨大になると思い、
自分の中でポイントとなる部分のみをのせています。

[TransactionJob]
transactionService.registList();

[TransactionSeriveImpl]
public void registList() {
List<String> list = new ArrayList<String>();

list.add("01");
list.add("02");
commit(list);
list.clear();

// "02"とう主キーはすでにDBに登録されているので、
// 例外が発生、ロールバックが行われる。
try {
list.add("03");
list.add("02");
commit(list);
rollback();

} catch (Exception e) {
System.out.println("例外が発生します。");
e.printStackTrace();
}

list.clear();
list.add("05");
list.add("06");
commit(list);
list.clear();
}

public void commit(List<String> list) {
SampleDto dto = new SampleDto();

for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
dto = createDummyDto(it.next());
mvndrMstrDAO.insert(dto);
System.out.println("登録");
}
System.out.println("コミット");
}

上記の検証のサンプルプログラムを実行後、"03"というデータがDBに格納されています。
想定結果では、ロールバックが発生し、"03"というデータは格納されないと思いました。

自分の中で考えられる原因としまして、以下の3つを考えています。
1.自動コミット無効設定ミス。
こちらの設定を行った後に、DB側でも自動コミットを無効する必要があるのか?
(まだOracleで自動コミットの設定ついては調べておらず、これから行う予定です。)
また、自分の考えている自動コミット無効設定が間違っており、他の設定方法があるのか?

2.トランザクション定義情報の設定ミス。
commitメソッドが呼び出されるregistList()メソッドを設定を行う必要があるのか?

3.ロールバック例外の設定ミス
ApplicationContextのロールバック例外の設定が間違っているのか?

インギさんのConnectionクラスのセーブポイントは面白そうなので、
検証が終わったら、さわってみたいなと思います。


長い文章になってしまいすいませんでした。
夢の中にもトランザクションが出てきました。。。
もしもし
ぬし
会議室デビュー日: 2004/10/15
投稿数: 280
投稿日時: 2007-10-10 12:30
Oracle RDBMS そのものには自動コミットは無いはず...。
(ミドルウェアとアプリケーション以外で聞いたことはないなぁ)
_________________
もしもし@RMAN 友の会
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-10-11 16:55
autoCommitを設定するのはtransactionManagerの仕事です。
#JtaTransactionManagerならさらに違う仕組みになります。

applicationContext.xmlにtransactionManagerが無さそうなのですが、
DataSourceTransactionManagerを設定しないと使えないのでは?
http://www.thinkit.co.jp/cert/compare/15/4/2.htm

あと、この要件ならセーブポイントも有効だと思います。
これならばエラーの直前までをコミットできますし。

アプリケーション全体を宣言的トランザクションで実装する
というポリシーに統一したいか、というような視点で考えて
選択すればいいと思います。
キタキツネ
常連さん
会議室デビュー日: 2006/11/23
投稿数: 32
お住まい・勤務地: 沖縄県名護市
投稿日時: 2007-10-20 14:02
自クラスのメソッドを呼んだ場合って、設定ファイルの情報って無視されるみたいですね。
例:
applicationContext
- A.abc()で例外発生時にrollbackするように指定

Aクラス
- abc() ・・・insert後、例外発生する処理を記載
- ddd() ・・・abc()メソッドをコール

Bクラス
- abc()メソッドを実行すると、DBには何も入っていない(rollback)
- ddd()メソッドを実行すると、DBにはデータが入っている(rollbackされない)

Spring(TransactionManagerになるのか?)って、こういう仕様なんですかね?
だとしたらちょっと使いずらいなぁ。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-10-20 17:21
>キタキツネさん
Spring AOPの仕様と実装の問題かと思います。
外部から呼び出した場合は間にProxyが存在してTXのインタセプタを実行しますが、
内部から呼び出した場合はProxyを経由しないためインタセプタを実行しないみたいです。

(以前確認したことがありますが、最近のバージョンでは確認していません)

Seasar2なら動的に拡張したクラスのインスタンスを直接生成しているので、
問題なく実行できますよ。
キタキツネ
常連さん
会議室デビュー日: 2006/11/23
投稿数: 32
お住まい・勤務地: 沖縄県名護市
投稿日時: 2007-10-22 17:35
>かつのりさん
返答ありがとうございます。
実は私のところでは、既にOSS構成が決まってしまっていてSpringは外せないのです。
形的にはあしゅさんの仰っていたように、コミット用のメソッドを作ってその内部でinsert等をやりたかったのですが・・ちと無理っぽいですね。

と、なると明示的にコミットするか、コミット/ロールバック用のクラスを作ってDIしておくかしかないってことですね・・
あとはAspectJとかで自前でAOPに引っ掛けてコミットですかね。んー・・悩む。。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-10-22 22:45
ProxyでTxが行われているので、
外側から実行するしかないでしょうね。

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