プロが教えるわが家の防犯対策術!

JdbcDaoSupportを継承したDaoAImpl、DaoBImplクラスがあり、DaoCImplで
A、Bの順にインターフェースを介してインスタンス化し、その順にそれぞれ
更新処理を走らせた時にDaoBImplでエラーが起こった場合、DaoAImplの更新処理を
ロールバックさせたいと思いますが現在DaoAImplの処理がコミットされてしまいます。
Testが実行クラスで、以下に現在の実装を記します。※ここではDBUtilsを使用

◆DAO(DaoBは同じ内容なので省略)
--------------------------------------------------------------
public class DaoAImpl extends JdbcDaoSupport implements DaoA {
/** DBコネクション */
private Connection con = null;

/** update */
public void execute(String sql) throws SQLException {
if (null == con) con = super.getConnection();

// 更新
QueryRunner qr = new QueryRunner();
qr.update(con, sql);
}
}
--------------------------------------------------------------
public class DaoCImpl implements DaoC {
/** update */
public void double_execute() throws SQLException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanFactory factory = (BeanFactory) context;
DaoA a = (DaoA) factory.getBean("daoA");
DaoB b = (DaoB) factory.getBean("daoB");

a.execute("UPDATE A_TABLE SET FLG = 2");
b.execute("UPDATE A_TABLE SET FLG = 3");
}
}
--------------------------------------------------------------
public class Test {
/** main */
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanFactory factory = (BeanFactory) context;
DaoC c = (DaoC) factory.getBean("daoC");

c.double_execute();
}
}
--------------------------------------------------------------

◆applicationContext.xml
--------------------------------------------------------------
~中略~
<!-- Transaction -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>

<bean id="txAttribute" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="*execute">PROPAGATION_REQUIRES_NEW, -SQLException</prop>
<prop key="select*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>

<bean id="txInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributeSource"><ref bean="txAttribute"/></property>
</bean>

<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref local="txInterceptor"/>
</list>
</property>
<property name="beanNames">
<list>
<value>dao*</value>
</list>
</property>
</bean>

<bean id="daoA" class="DaoAImpl">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="daoB" class="DaoBImpl">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="daoC" class="DaoCImpl">
</bean>

</beans>
--------------------------------------------------------------
以上、お手数ですがご指摘お願い致します。

A 回答 (4件)

QueryRunnerはorg.apache.commons.dbutils.QueryRunnerでしょうか?


トランザクション処理を実行するクラスにSpringを
使用していないので、当然宣言的トランザクションは実現できません。
org.springframework.jdbc.object.SqlUpdateを継承した
RDBMSオペレーションクラスを作成し、本クラスのupdateメソッドに
SqlParameterクラスでパラメータを指定して
トランザクション処理を実行します。

【サンプル】
----------------------------------------------
private static class InsertOwnerQuery extends SqlUpdate {
private static final String SQL_INSERT
= "insert into OWNER(OWNER_ID, OWNER_NAME) values(?, ?)";

private InsertOwnerQuery(DataSource ds) {
super(ds, SQL_INSERT);
super.declareParameter(new SqlParameter("ownerId", Types.VARCHAR));
super.declareParameter(new SqlParameter("ownerName", Types.VARCHAR));
}

// 挿入処理のヘルパーメソッド
private int insert(String ownerId, String ownerName) {
Object[] param = {ownerId, ownerName};
return update(param);
}
}
-------------------------------------------------
XMLの設定に関しては、SQLException発生時にRollbackする設定を
されているようですので、発生させる例外がSQLExceptionであれば
問題なくRollbackされるはずです
(念の為、XMLには、java.sql.SQLExceptionとしておいて方がいいかも)。
後は前回指摘したようにPROPAGATION_REQUIREDを設定すれば大丈夫だと思います。
    • good
    • 0
この回答へのお礼

度々のご返信、誠にありがとうございます。

ご指摘の内容を検証させて頂きましたが結果は同じでした。
当方でも色々調べました結果、DaoA及びDaoBとDaoCを別々で新規生成した
ApplicationContextオブジェクトから取得していたのを、DaoCを取得した時点で
DaoA、DaoBもインジェクションされるようにapplicationContext.xmlとDaoCImplを
以下のように修正しました所、当初の想定の動きになりました。
ApplicationContext毎にAutoProxyの管理が行われているような感じがします。

◆1.applicationContext.xml
<bean id="daoC" class="DaoCImpl">
<property name="daoA">
<ref bean="daoA"/>
</property>
<property name="daoB">
<ref bean="daoB"/>
</property>
</bean>

◆2.DaoCImpl 追加コード
private DaoA daoA = null;
private DaoB daoB = null;

public DaoA getDaoA() { return daoA; }
public void setDaoA(DaoA daoA) { this.daoA = daoA; }
public DaoB getDaoB() { return daoB; }
public void setDaoB(DaoB daoB) { this.daoB = daoB;}

◇参考URL
http://static.springframework.org/spring/docs/2. …
※BeanPostProcessors and AOP auto-proxyingの項
Bean 'autoProxyCreator' is not eligible for getting processed
by all BeanPostProcessors (for example: not eligible for auto-proxying)

お礼日時:2008/03/23 01:22

> コネクションを


> DaoCImplのみで取得して...
そうすると、私の最初の回答のように、単一のトランザクションスコープになりますよね?。(想像ですが)

XMLのレベルでなく、あくまでもプログラムのレベルで検討してください!。
    • good
    • 0

applicationContext.xmlに


「PROPAGATION_REQUIRES_NEW」を指定しているのが原因と思われます。
上記を指定すると新たなトランザクションを開始してしまいます。
PROPAGATION_REQUIREDなどを指定すると、トランザクションが開始されていれば同一トランザクションで実行するように動作します。
詳しくは参考URLを見てみてください。

参考URL:http://www.techscore.com/tech/Others/Spring/6.html
    • good
    • 0
この回答へのお礼

ご指摘ありがとうございます。以下のようにPROPAGATION_REQUIREDを指定しても結果は同じでした。
<prop key="*execute">PROPAGATION_REQUIRED, -SQLException</prop>

念の為、合わせて以下のように記述するとDaoAImpl、DaoBImpl両方の処理がコミットされました。
<property name="beanNames">
<list>
<value>daoC</value>
</list>
</property>

現在DaoAImpl、DaoBImplのコミットが独立して行われているような感じですので、コネクションを
DaoCImplのみで取得してDaoAImpl、DaoBImplではJdbcDaoSupportを継承やコネクションを取得したりせず
DaoCImplから引数としてコネクションを渡して処理をさせると、想定通り両方の処理がロールバックされる事は確認しています。

よく分かりませんがJdbcDaoSupportを継承したクラス単位で管理されているような印象です。

お礼日時:2008/02/26 08:57

詳細はよく見えませんが、二つの処理が一つのトランザクション管理スコープ内に包まれていないのではないですか。



一つのトランザクション管理スコープとは、単純化して例示すると:
try{
 con.setAutoCommit(false);
  ...
  ...
  ...
 con.commit();
}
catch (.....){
 con.rollback();
}
etc., etc.
    • good
    • 0
この回答へのお礼

ご返信ありがとうございます。DaoCImplのdouble_executeが正常終了すると
トランザクションがコミットされるようにapplicationContext.xmlで
指定したつもりがうまくいっていない状況です。
クラスが悪いのか設定が悪いのかどっちも悪いのか謎です。

お礼日時:2008/02/23 23:35

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!