This is my situation:
- a Postgres database where I have only Spring Batch tables
- an Oracle database where I have business data to read, write and update
I have tried to configure an XA enviroment with Atomikos and it seems to work but honestly I haven't understand what is exactly happening.
- Can you check my configuration, please? I'm totally noob in these things...
- If I set "hibernate.transaction.jta.platform" to "com.atomikos.icatch.jta.hibernate4.AtomikosPlatform" instead of my class "SpringJtaPlatformAdapter" it seems that the batch doesn't commit on my Postgres DB. Why?
- For testing I was using Spring "JpaPagingItemReader". With this reader I get always the exception "java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()" so I copied this solution: solution Why I need to do this? Is there another JpaReader for XA?
Thanks a lot for your help.
Here my configuration:
- spring-batch-core 3.0.7.RELEASE
- spring-jdbc and spring-orm 4.0.5.RELEASE
- hibernate-entitymanager 5.0.7.Final
- Atomikos transactions-jta, transactions-jdbc, transactions-hibernate4 4.0.6
database.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="oracleDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource" />
<property name="uniqueResourceName" value="oracleDS" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="3"/>
<property name="testQuery" value="select * from dual" />
<property name="xaProperties">
<props>
<prop key="URL">${database.oracle.url}</prop>
<prop key="user">${database.oracle.username}</prop>
<prop key="password">${database.oracle.password}</prop>
</props>
</property>
</bean>
<bean id="postgresDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName" value="org.postgresql.xa.PGXADataSource" />
<property name="uniqueResourceName" value="postgresDS" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="3"/>
<property name="testQuery" value="select * from batch_job_execution" />
<property name="xaProperties">
<props>
<prop key="serverName">localhost</prop>
<prop key="databaseName">postgres</prop>
<prop key="user">${database.postgresql.username}</prop>
<prop key="password">${database.postgresql.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">coriTransactionManager</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">
<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>
<alias name="mainTransactionManager" alias="transactionManager" />
<!-- inject the Atomikos transaction manager into a Spring Hibernate adapter for JTA Platform -->
<bean id="springJtaPlatformAdapter" class="com.mydomain.jta.SpringJtaPlatformAdapter">
<property name="jtaTransactionManager" ref="mainTransactionManager" />
</bean>
<bean id="entityManagerFactoryOracle" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
depends-on="mainTransactionManager,springJtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="persistenceUnitName" value="oraclePersistenceUnit" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapterOracle"/>
<property name="dataSource" ref="oracleDataSource" />
<property name="jpaPropertyMap" ref="jpaPropertyMapOracle"></property>
</bean>
<bean id="jpaVendorAdapterOracle" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false"/>
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
<util:map id="jpaPropertyMapOracle">
<entry key="hibernate.transaction.jta.platform" value="com.mydomain.jta.SpringJtaPlatformAdapter" />
<!-- <entry key="hibernate.transaction.jta.platform" value="com.atomikos.icatch.jta.hibernate4.AtomikosPlatform"/> -->
</util:map>
</beans>
context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="postgresDataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseType" value="POSTGRES" />
<property name="isolationLevelForCreate" value="ISOLATION_DEFAULT"/>
</bean>
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
</beans>
SpringJtaPlatformAdapter
public class SpringJtaPlatformAdapter extends AbstractJtaPlatform {
private static final long serialVersionUID = 1L;
private static TransactionManager sTransactionManager;
private static UserTransaction sUserTransaction;
@Override
protected TransactionManager locateTransactionManager() {
return sTransactionManager;
}
@Override
protected UserTransaction locateUserTransaction() {
return sUserTransaction;
}
public void setJtaTransactionManager(JtaTransactionManager jtaTransactionManager) {
sTransactionManager = jtaTransactionManager.getTransactionManager();
sUserTransaction = jtaTransactionManager.getUserTransaction();
}
}