Сущность JPA не сохраняется при использовании в распределенной транзакции - PullRequest
0 голосов
/ 25 февраля 2019

Я пытаюсь создать приложение, которое может сохранять как JPA, так и Mongo объекты, используя Spring boot.Я реализовал MongoResourceManager и JPAResourceManager с помощью XAResource.JPAResourceManager не сохранит данные, пока не будет явно вызван entityManager.flush ().

JTA config

<bean class="org.springframework.transaction.jta.JtaTransactionManager"
    id="transactionManager" lazy-init="true">
    <property name="transactionManager">
        <bean
            class="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple" />
    </property>
    <property name="userTransaction">
        <bean class="com.arjuna.ats.jta.UserTransaction" factory-method="userTransaction" />
    </property>
</bean>

JPA Config

<tx:annotation-driven proxy-target-class="true" />
  <bean
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    id="oracleEMForacle1" lazy-init="true" primary="true">
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.format_sql">true</prop>
            <prop key ="hibernate.jdbc.batch_size">50</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle12cDialect</prop>
            <prop key="hibernate.transaction.jta.platform">org.hibernate.engine.transaction.jta.platform.internal.JBossStandAloneJtaPlatform
            </prop>
            <prop key="hibernate.flushMode">commit</prop>
            <prop key="hibernate.use_sql_comments">true</prop>
        </props>
    </property>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="org.hibernate.dialect.Oracle12cDialect" />
            <property name="generateDdl" value="true" />
            <property name="showSql" value="false" />
        </bean>
    </property>
    <property name="jtaDataSource">
        <bean class="org.apache.commons.dbcp2.BasicDataSource">
            <property name="connectionProperties"
             value="password=${password};user=${username}"></property>
            <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
            <property name="url" value="${url}" />
        </bean>
    </property>
    <property name="packagesToScan">
        <array>
            <value>com.test.jpa.jpaentity</value>   
        </array>
    </property>
</bean>

JPAResourceManager

public class JpaResourceManager extends ResourceManagerCommon implements XAResource 
{

    private static final XLogger logger = XLogger.getXLogger(JpaResourceManager.class);

    private EntityManager em;

    public JpaResourceManager(PersistanceAgent<EntityManagerFactory> persistanceAgent) {
        super(persistanceAgent);
    }

    /**
     * EntityManagerFactory will be retrieved from ConfigurableApplicationContext 
     */ 
    @Override
    public void start(Xid xid, int i) throws XAException {
        EntityManagerFactory emf = this.persistanceAgent.getDataSource();
        this.em = emf.createEntityManager();
    }

    @Override
    public int prepare(Xid xid) throws XAException {
        try {
            ITxArea txArea = getTxArea();
            em.joinTransaction();
            for (EntityWithOperation entity : txArea.values()) {
               em.persist(entity);
            }   
            //this.em.flush(); // Explicitly calling flush
        } catch (Exception e) {
            throw new XAException(XAException.XAER_RMERR);
        } 
        return XA_OK;
    }

    @Override
    public void commit(Xid xid, boolean isLocalTransaction) throws XAException {
        if (em.isOpen()) {
            em.clear();
            em.close();
        }
    }

    @Override
    public Xid[] recover(int i) throws XAException {
        return new Xid[0];
    }

    @Override
    public void rollback(Xid xid) throws XAException {
        logger.warn("JPA ResourceManager ROLLBACK called..");
        closeEntityManager(this.em);
    }

    @Override
    public boolean setTransactionTimeout(int i) throws XAException {
        return false;
    }

    @Override
    public void end(Xid xid, int i) throws XAException {
    }

    @Override
    public void forget(Xid xid) throws XAException {
    }

    @Override
    public int getTransactionTimeout() throws XAException {
        return 0;
    }

    @Override
    public boolean isSameRM(XAResource xaResource) throws XAException {
        return false;
    }
}
...