- PR -

テーブル更新処理を全件終えた後にコミットしたい

投稿者投稿内容
たまこ
常連さん
会議室デビュー日: 2005/01/12
投稿数: 25
投稿日時: 2005-04-20 14:33
お世話になります。
seasar、hibernateを用いて開発をしています。
トランザクションは、JTAのUserTransactionを使っています。
以下のような場合(全てのUPDATEが終わったあとにcommit)では、
1件ごとにcommitされてしまいます。

------------------------------------------------------------
 protected S2Container container;
 public S2SessionFactory factory;
 factory = (S2SessionFactory) du.getSessionFactory();
 S2Session session = factory.getSession();

 // トランザクションを始めます
 UserTransaction ut = (UserTransaction)container.getComponent(
            UserTransaction.class);
 if (ut != null){
  ut.begin();
 }
 // テーブル(UserTbl)の型
 UserTbl usertbl = null;

 // 対象件数分処理を行います
 for (j = 0 ; j < lineCnt ; j++){
  for (i = 0 ; i < 10 ; i++){
   String param = uid[j][i];
   // 検索対象のデータ取得
   List result = session.find("from UserTbl as u where u.userId = ?",
          param,Hibernate.STRING);
   if (result.size() > 0) {
    usertbl = (UserTbl) result.get(0);
   } else {
    try {
     // データ不整合 ロールバック 処理終了
     ut.rollback();
    }
    return false;
   }
   // 現在の年齢に1足した数で更新します
   int userAge = usertbl.getAge() + 1;
   usertbl.setAge(userAge);
   session.update(usertbl);
   i++;
  }
  j++;
 }
 // 全対象レコードの処理終了でコミットします
 ut.commit();

------------------------------------------------------------

上記の「session.update(usertbl);」部分で既にコミットされている感じです。
これを、全ての対象レコードの更新処理が完了したあとに、一斉にコミットしたいのですが、どのようにすれば実現できますでしょうか。

是非是非ご教授お願い致します。



[ メッセージ編集済み 編集者: たまこ 編集日時 2005-04-20 16:24 ]
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-04-20 21:39
オートコミットがtrueになってたりしてませんかね。。。
たまこ
常連さん
会議室デビュー日: 2005/01/12
投稿数: 25
投稿日時: 2005-04-20 22:19
ご指摘ありがとうございます。

書込みしてからも色々と調べていて、
仰せの通り、autoCommitがtrueになっていたので、
S2Session session = factory.getSession(); の下に
session.connection().setAutoCommit(false);
と付け加え、falseにしました。

session.update(usertbl);
の時に即コミットされていたのは避けられましたが、
2件目の以下のロジックの際にコミットされてしまいます。

// 検索対象のデータ取得
   List result = session.find("from UserTbl as u where u.userId = ?",
          param,Hibernate.STRING);

sessionに何かウラがありそうなのですが・・・。
コミットを回避するにはどうしたら良いでしょうか。。。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-04-20 23:04
S2のJTA(AOP)を使っていますよね。
DEBUGレベルでログが出力されると思います。
Log4JのプロパティでDEBUGレベルのログを有効にして、
何が行われているか調べてみてはいかがですが。

Hibernateは使ったことがないのでゴメンナサイ・・・
すえぞう
会議室デビュー日: 2004/08/11
投稿数: 9
投稿日時: 2005-04-21 01:08
セッションの取得方法が異なりますが、前に下記のようにしました。

session = HibernateUtils.getSessionFactory().openSession();

// commit時の場合のみオブジェクトとデータベースが同期されるように設定。
session.setFlushMode(FlushMode.COMMIT);

JTAで同じことをしてよいのかわかりませんが。
Anthyhime
ぬし
会議室デビュー日: 2002/09/10
投稿数: 437
投稿日時: 2005-04-21 06:56
JTAを利用するのであればautocommitをユーザーが独自に変更してはいけません。
デフォルトで問題ありません。
そもそもJTAを利用する場合はデータソースがXAデータソースでなければなりません。
またコネクションの取得もJTAのトランザクション境界内で行わなければなりません。
ここら辺で解決しないでしょうか?
Anthyhime
ぬし
会議室デビュー日: 2002/09/10
投稿数: 437
投稿日時: 2005-04-21 07:04
また処理を見る限りJTAを利用しないといけないような複雑な処理でもない気がします。2層コミットは複数のトランザクションリソースを利用したりする場合にやむなく利用するものです。まぁEJBはかなり積極的に利用していますが・・・・。
たまこ
常連さん
会議室デビュー日: 2005/01/12
投稿数: 25
投稿日時: 2005-04-22 13:51
アドバイスをくださった皆様、どうもありがとうございます。
書き込みが遅くなり、申し訳ありません。

色々と関連文章を読み漁っているうちに、私自身トランザクションの考え方が間違っていることに気づきました。
トランザクションは、そのWebアプリの開始から終了までで1つなんですね。

Anthyhime様のおっしゃる通り、autoCommitの値は関係がなく、
「メソッドでExceptionが投げられたらTransaction内の処理を全てrollbackしてくれる」ということがわかりました。
現在、Transactionの制御を明示的にコード内へ記述することをやめ、
また、上記のように、子メソッドで投げたExceptionを親メソッドでcatchするように変更しましたが、
未だにrollbackしてくれません。
Transaction(AOP)ですが、親メソッドのaspect pointcutをrequiredTx、
子メソッドをmandatoryTxにしていますが、
問題なくTransactionは親から開始しているように思われます。
(子メソッドでTransactionが開始されていないというエラーが発生しない為。)

かつのり様の仰るとおり、log4jのDEBUGレベルのログを出力させてみましたが、
Transactionに関するログは出力されていませんでした。
但し、hibernateの設定ファイル(hibernate.cfg.xml)にTransactionについて記述するプロパティがあり、以下のように記述しています。

<hibernate-configuration>
 <session-factory>
  <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
  <property name="show_sql">true</property>
  <property name="hibernate.transaction.factory_class">
    net.sf.hibernate.transaction.JTATransactionFactory
  </property>
  <property name="jta.UserTransaction">
    java:comp/UserTransaction
  </property>
  <mapping resource="hoge/entity.hbm.xml"/>
  <class-cache usage="read-write" class="hoge.UserTbl" />
 </session-factory>
</hibernate-configuration>

これは合っているのでしょうか。
飽くまでhibernateの設定ファイルなので、使用するTransactionFactoryがhibernateのものであっても、
関係はないのでしょうか。
とはいっても、SeasarやJTAに同じ類のTransactionFactoryが見当たらなかったのですが・・・。

データソースはj2ee.diconで指定しています。
<component name="xaDataSource" class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
 <property name="driverClassName">
  "org.gjt.mm.mysql.Driver"
 </property>
 <property name="URL">
  "jdbc:mysql://localhost/hoge"
 </property>
 <property name="user">"hoge"</property>
 <property name="password">"****"</property>
</component>

どうしてrollbackしてくれないのでしょうか。。。
申し訳ありませんが、アドバイス・ご指導等よろしくお願いします。

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