14

次のコード(春3):

@Transactional("txManager")
public class DaoHolder {

    @Transactional(value="txManager", readOnly=false, propagation=Propagation.REQUIRES_NEW, rollbackFor={Exception.class})
    private void runTransactionalMethod() throws Exception {
        dao1.insertRow();
        dao2.insertRow();
        //throw new Exception();
    }
    //...
}
  • dao1は、datasource1に接続されたセッションファクトリを使用します
  • dao2は、datasource2に接続されたセッションファクトリを使用します
  • txManagerは、dao1と同じセッションファクトリを使用するHibernateTransactionManagerです。

上記のコードは、トランザクション方式で正しく機能します。特に、例外がスローされない場合、各dao操作は(2つの異なるデータソースに)コミットされます。例外がスローされると、各dao操作はロールバックされます。

私の質問は:なぜそれが機能するのですか?私が読んだところはどこでも、複数のデータソースを処理するときにJtaTransactionManagerを使用するように言われました。JTAは使いたくないです。HibernateTransactionManagerで実行したままにすると、どのような結果になる可能性がありますか?



興味のある方のためのいくつかの詳細:

各データソースは次のように定義されています。

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="initialSize" value="${jdbc.initial_size}" />
    <property name="maxActive" value="${jdbc.max_active}" />
</bean>

各セッションファクトリは次のように定義されます。

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mappingResources">
        <list>
            ... multiple *.hbm.xml files here ...
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
            <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
        </props>
    </property>
</bean>

トランザクションマネージャーは次のように定義されます。

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

各daoクラスはHibernateDaoSupportを拡張し、insertRowメソッドの内容はdao1の場合とほぼ同じです。

getHibernateTemplate().save(obj);

およびdao2の場合:

getHibernateTemplate().merge(obj);
4

1 に答える 1

14

質問:

私はちょうどこの 1 日をまさにこの質問に取り組んでいたところです。データ ソース間のトランザクションが 1 つの休止状態のトランザクション マネージャーで機能しているように見えるのはなぜですか?

あなたと同じように、私も複数の場所で JtaTransactionManager を使用する必要があることを読みました...そして、それらが正しかったことがわかりました! 説明します:

構成:

あなたと同じように、私は 2 つのデータ ソース、2 つのセッション ファクトリ、1 つの HibernateTransactionManager から始めました。

私のテスト コードもあなたのものと非常によく似ていて、オブジェクトを両方のデータベースに正常に保存できました。手動で例外をスローした場合、どちらの保存もデータベースに表示されません。そのため、両方が正しくロールバックされているように見えました。ただし、休止状態のデバッグ ログをオンにすると、どちらの保存も実際にはデータベースに送信されていないことがわかり、ロールバックするものは何もありませんでした

The problem is in the test, so I'll change your test to prove that the single transaction manager is actually not working!

The change we need was suggested by JB Nizet on Jan 2:

Have you tried calling flush on both sessions before throwing the exception?


A better test:

First, add a flush function to each of your DAO's. This is what mine looks like:

public void flush() {
    sessionFactory.getCurrentSession().flush();
}

Yours will probably look like this:

public void flush() {
    getHibernateTemplate().flush();
}

Now, modify your test to flush each dao before the exception:

 @Transactional("txManager")
public class DaoHolder {

    @Transactional(value="txManager", readOnly=false, propagation=Propagation.REQUIRES_NEW, rollbackFor={Exception.class})
    private void runTransactionalMethod() throws Exception {
        dao1.insertRow();
        dao2.insertRow();

        dao1.flush();
        dao2.flush();

        throw new Exception();
    }
    //...
}

The result:

Only the datasource associated to txManager is rolled back. That makes sense, because txManager does not know about the other data source.

Summary:

In my case, I do not need to access 2 databases in one transaction, separate transactions is fine. So I simply defined a second transaction manager:

<bean id="txManager2" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory2"/>
</bean>

そして、2 番目のデータベースにアクセスするたびに、Transactional アノテーションでこれを名前で参照しました。

@Transactional(value="txManager2"...)


2 番目のデータベースの注釈付きトランザクションを取得できるようになりましたが、まだ両方のデータベースでトランザクションを取得できません。そのためにはJtaTransactionManagerが必要なようです。

于 2012-04-03T20:53:26.480 に答える