2

私がする必要があるのは、3 つの異なる Oracle データベースにわたる分散トランザクションです。それぞれの 1 つは JDBC を介してアクセスする必要があり、残りの 2 つは Hibernate を介してアクセスする必要があります。これが私のAtomikos構成です:

<bean id="mainDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
    init-method="init" destroy-method="close">
    <property name="xaDataSourceClassName" value="${mainDataSource.jdbc.className}" />
    <property name="uniqueResourceName" value="${mainDataSource.jdbc.uniqueName}" />
    <property name="poolSize" value="${mainDataSource.jdbc.maxPoolSize}" />
    <property name="testQuery" value="${mainDataSource.jdbc.testQuery}" />
    <property name="xaProperties">
        <props>
            <prop key="URL">${mainDataSource.jdbc.url}</prop>
            <prop key="user">${mainDataSource.jdbc.user}</prop>
            <prop key="password">${mainDataSource.jdbc.password}</prop>
        </props>
    </property>
</bean>

<bean id="optionalDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
    init-method="init" destroy-method="close">
    <property name="xaDataSourceClassName" value="${optionalDataSource.jdbc.className}" />
    <property name="uniqueResourceName" value="${optionalDataSource.jdbc.uniqueName}" />
    <property name="poolSize" value="${optionalDataSource.jdbc.maxPoolSize}" />
    <property name="testQuery" value="${optionalDataSource.jdbc.testQuery}" />
    <property name="xaProperties">
        <props>
            <prop key="URL">${optionalDataSource.jdbc.url}</prop>
            <prop key="user">${optionalDataSource.jdbc.user}</prop>
            <prop key="password">${optionalDataSource.jdbc.password}</prop>
        </props>
    </property>
</bean>

<bean id="eventDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
    init-method="init" destroy-method="close">
    <property name="xaDataSourceClassName" value="${eventDataSource.jdbc.className}" />
    <property name="uniqueResourceName" value="${eventDataSource.jdbc.uniqueName}" />
    <property name="poolSize" value="${eventDataSource.jdbc.maxPoolSize}" />
    <property name="testQuery" value="${eventDataSource.jdbc.testQuery}" />
    <property name="xaProperties">
        <props>
            <prop key="URL">${eventDataSource.jdbc.url}</prop>
            <prop key="user">${eventDataSource.jdbc.user}</prop>
            <prop key="password">${eventDataSource.jdbc.password}</prop>
        </props>
    </property>
</bean>

<bean id="atomikosTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp"
    init-method="init" destroy-method="shutdownForce">
    <constructor-arg>
        <props>
            <prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactory
            </prop>
            <prop key="com.atomikos.icatch.tm_unique_name">${transactionmanager.atomikos.tmId}</prop>
            <prop key="com.atomikos.icatch.enable_logging">${transactionmanager.atomikos.enablelogging}</prop>
            <prop key="com.atomikos.icatch.output_dir">${transactionmanager.atomikos.console}</prop>
            <prop key="com.atomikos.icatch.log_base_dir">${transactionmanager.atomikos.tmLog}</prop>
            <prop key="com.atomikos.icatch.log_base_name">${transactionmanager.atomikos.tmLogBaseName}</prop>
        </props>
    </constructor-arg>
</bean>

<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"
    depends-on="atomikosTransactionService">
    <property name="transactionTimeout" value="300" />
</bean>

<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
    init-method="init" depends-on="atomikosTransactionService"
    destroy-method="close">
    <!-- when close is called, should we force transactions to terminate or 
        not? -->
    <property name="forceShutdown" value="true" />
    <property name="startupTransactionService" value="false" />
</bean>

<bean id="mainTransactionManager"
    class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="atomikosTransactionManager" />
    <property name="userTransaction" ref="atomikosUserTransaction" />
</bean>

<!-- Der mainTransactionManager ist der Default-TransactionManager von Spring. -->
<alias name="mainTransactionManager" alias="transactionManager" />

Hibernate 構成は、このトピックで見つかったソリューションに触発されています。

<!-- inject the Atomikos transaction manager into a Spring Hibernate adapter 
    for JTA Platform -->
<bean id="springJtaPlatformAdapter"
    class="my.domain.spring.hibernate.jta.SpringJtaPlatformAdapter">
    <!-- the mainTransactionManager is defined in ora_jtam_atomikos.xml imported -->
    <property name="jtaTransactionManager" ref="mainTransactionManager" />
</bean>

<bean id="entityManagerFactoryEVL"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    depends-on="mainTransactionManager,springJtaPlatformAdapter">
    <property name="persistenceXmlLocation" value="classpath:evl_persistence.xml" />
    <property name="persistenceUnitName" value="evlPersistenceUnit" />
    <property name="dataSource" ref="optionalDataSource" />
    <property name="loadTimeWeaver">
        <bean
            class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
    </property>
    <property name="jpaPropertyMap" ref="jpaPropertyMapEVL"></property>
</bean>

<util:map id="jpaPropertyMapEVL">
    <entry key="hibernate.hbm2ddl.auto" value="validate" />
    <entry key="hibernate.show_sql" value="false" />
    <entry key="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
    <entry key="hibernate.transaction.jta.platform"
        value="my.domain.spring.hibernate.jta.SpringJtaPlatformAdapter" />
</util:map>

<bean id="entityManagerFactoryVVL"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    depends-on="mainTransactionManager,springJtaPlatformAdapter">
    <property name="persistenceXmlLocation" value="classpath:vvl_persistence.xml" />
    <property name="persistenceUnitName" value="vvlPersistenceUnit" />
    <property name="dataSource" ref="eventDataSource" />
    <property name="loadTimeWeaver">
        <bean
            class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
    </property>
    <property name="jpaPropertyMap" ref="jpaPropertyMapVVL"></property>
</bean>

<util:map id="jpaPropertyMapVVL">
    <entry key="hibernate.hbm2ddl.auto" value="validate" />
    <entry key="hibernate.show_sql" value="false" />
    <entry key="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
    <entry key="hibernate.transaction.jta.platform"
        value="my.domain.spring.hibernate.jta.SpringJtaPlatformAdapter" />
</util:map>

そして、 SpringJtaPlatformAdapter という名前の小さなクラス:

public class SpringJtaPlatformAdapter extends AbstractJtaPlatform {
  private static final long serialVersionUID = -7030175748923257913L;
  private static TransactionManager sTransactionManager;
  private static UserTransaction sUserTransaction;

  @Override
  protected TransactionManager locateTransactionManager() {
    Assert.notNull(sTransactionManager, "TransactionManager has not been setted");
    return sTransactionManager;
  }

  @Override
  protected UserTransaction locateUserTransaction() {
    Assert.notNull(sUserTransaction, "UserTransaction has not been setted");
    return sUserTransaction;
  }

  public void setJtaTransactionManager(JtaTransactionManager jtaTransactionManager) {
    sTransactionManager = jtaTransactionManager.getTransactionManager();
    sUserTransaction = jtaTransactionManager.getUserTransaction();
  }

}

バッチを実行すると、次のことを確認できました。

  1. アトミコスのatomikosUserTransactionとが最初に構築されますatomikosTransactionManager
  2. mainTransactionManager直後に初期化されます
  3. myのsetJtaTransactionManagerメソッドSpringJtaPlatformAdapterが呼び出され、 と の両方のメモリ アドレスが以前に作成されたものと一致sTransactionManagerするsUserTransaction
  4. locateTransactionManagerSpringJtaPlatformAdapter2 回呼び出されます (持続性ユニットごとに 1 つ)。
  5. その後、Hibernate コードが実行され、エンティティが正しく初期化されます
  6. JDBC 経由でアクセスされるデータベースが更新されます
  7. Hibernate を介してアクセスされるデータベースは更新されません (ロールバックが行われたかのように)。

実行中、ログに警告が 1 つだけ表示されます。

WARN main SessionFactoryImpl:1530 - HHH000008: JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()

たぶんそれが役立つかもしれませんが、個人的には警告メッセージが表示されません。

Maven によると、Spring ORM 3.2.0 と Hibernate 4.2.3 および Atomikos 3.8.0 を使用しています。

4

2 に答える 2

0

同僚の 1 人が、休止状態のデータベースが更新されなかった理由を発見しました。私は persistence.xml にこれを持っていました:

<persistence-unit name="evlPersistenceUnit" transaction-type="RESOUCE_LOCAL">

Atomikos の場合、次のように配置する必要がありました。

<persistence-unit name="evlPersistenceUnit" transaction-type="JTA">

今では問題なく動作しています。

于 2015-03-03T12:05:35.603 に答える