Reputation: 725
What I need to do is a distributed transaction over three distinct Oracle databases. One of each must be accessed through JDBC, the two others through Hibernate. Here is my Atomikos configuration :
<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" />
The Hibernate configuration is inspired by the solution found on this topic :
<!-- 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>
And the small class named 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();
}
}
When I do run the batch, I could verified that :
atomikosUserTransaction
and atomikosTransactionManager
of
Atomikos are constructed firstmainTransactionManager
is initialized right aftersetJtaTransactionManager
method of my SpringJtaPlatformAdapter
is called, both memory addresses for the sTransactionManager
and sUserTransaction
are consistent with the ones created beforelocateTransactionManager
of the SpringJtaPlatformAdapter
is called twice (one for each persistence unit)During the run, only one warning appears in the logs :
WARN main SessionFactoryImpl:1530 - HHH000008: JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()
Maybe that can help, I personnaly don't get the warning message.
According to Maven, I'm using Spring ORM 3.2.0 with Hibernate 4.2.3 and Atomikos 3.8.0.
Upvotes: 2
Views: 4696
Reputation: 20135
I am using Atomikos 4.0.0.M4 release with:
<entry key="hibernate.transaction.jta.platform"
value="com.atomikos.icatch.jta.hibernate4.AtomikosPlatform"/>
instead of:
<entry key="hibernate.transaction.manager_lookup_class"
value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
The point to note is that Hibernate 4.x moved away from TransactionManager to JtaPlatform which has necessitated the need for the change in configuration.
I am happy with the functionality provided by Atomikos and it has been running stably for me.
Upvotes: 3
Reputation: 725
One colleague found why my hibernate databases were not updated. I had this in my persistence.xml :
<persistence-unit name="evlPersistenceUnit" transaction-type="RESOUCE_LOCAL">
For Atomikos, I should have placed :
<persistence-unit name="evlPersistenceUnit" transaction-type="JTA">
Now it's working just fine.
Upvotes: 0