Spring批处理:如何配置xa事务

这是我的情况:

  • 一个Postgres数据库,我只有Spring Batch表

  • 一个Oracle数据库,我可以在其中读取,写入和更新业务数据

我试图用Atomikos配置一个XA环境,它似乎工作但老实说我不明白究竟发生了什么 .

  • 你能检查一下我的配置吗?我在这些事情上完全是菜鸟......

  • 如果我将"hibernate.transaction.jta.platform"设置为"com.atomikos.icatch.jta.hibernate4.AtomikosPlatform"而不是我的类"SpringJtaPlatformAdapter",那么批次似乎没有在我的Postgres DB上提交 . 为什么?

  • 测试我使用的是Spring "JpaPagingItemReader" . 有了这个阅读器,我总是得到异常"java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()"所以我复制了这个解决方案:solution为什么我需要这样做?还有另一个XA的JpaReader吗?

非常感谢你的帮助 .

在这里我的配置:

  • spring-batch-core 3.0.7.RELEASE

  • spring-jdbc和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();
    }
}

回答(0)