0

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.

  1. Can you check my configuration, please? I'm totally noob in these things...
  2. 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?
  3. 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();
    }
}
Andrea
  • 61
  • 10
  • From the requirements you've described it doesn't seem that you need an XA transaction manager. Is there something maybe I'm not understanding that would require it? – Joe Chiavaroli Feb 21 '18 at 22:41
  • Why I don't need an XA transaction manager? I have the Spring batch tables inside a Postgres DB and my business tables inside an Oracle DB – Andrea Feb 22 '18 at 09:44
  • My apologies it wasn't clear to me when I originality (mis)read it that the batch tables had to be in the source db. – Joe Chiavaroli Feb 22 '18 at 12:35

0 Answers0