Spring、EclipseLink、Jboss eap 7 with XA 数据源

Spring, EclipseLink, Jboss eap 7 with XA datasource

我们正在将此应用程序从 Weblogic 迁移到 Jboss。 应用程序在 weblogic XA 数据源中工作,甚至在非 XA 的 Jboss 中工作。但它在 Jboss XA 数据源中不工作....

在 Jboss XA 数据源中获取以下异常

2018-11-02 15:04:34,003 ERROR [com.hf.pi.esign.dao.db.ActivityDBDAOImpl] (default-threads - 4) ERROR SAVING ENTITY :: com.hf.pi.esign.dao.db.entity.OpportunityEntity@4753c567 For id :: null: javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DatabaseException
        Internal Exception: java.sql.SQLException: IJ031017: You cannot set autocommit during a managed transaction
        Error Code: 0
        Query: InsertObjectQuery(com.hf.pi.esign.dao.db.entity.OpportunityEntity@4753c567)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:879)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
    at com.sun.proxy.$Proxy87.flush(Unknown Source)
    at com.hf.pi.esign.dao.db.ActivityDBDAOImpl.saveEntity(ActivityDBDAOImpl.java:122)
    at com.hf.pi.esign.dao.db.ActivityDBDAOImpl.saveOpportunity(ActivityDBDAOImpl.java:157)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
    at com.sun.proxy.$Proxy88.saveOpportunity(Unknown Source)
    at com.hf.pi.esign.service.profile.ProfileServiceImpl.saveConsumerOpportunity(ProfileServiceImpl.java:124)
    at com.hf.pi.esign.service.esignstatusnotification.StatusNotificationServiceImpl.logOpportunity(StatusNotificationServiceImpl.java:237)
    at com.hf.pi.esign.service.esignstatusnotification.StatusNotificationServiceImpl.process(StatusNotificationServiceImpl.java:371)
    at com.hf.pi.esign.service.esignstatusnotification.StatusNotificationServiceImpl.processNotificationStatusInternal(StatusNotificationServiceImpl.java:203)
    at com.hf.pi.esign.service.esignstatusnotification.StatusNotificationServiceImpl.processNotificationStatus(StatusNotificationServiceImpl.java:113)
    at com.hf.pi.esign.mdb.StatusNotificationProcessor.process(StatusNotificationProcessor.java:87)
    at com.hf.pi.esign.mdb.AbstractConsumerMDB.onMessageInternal(AbstractConsumerMDB.java:90)
    at com.hf.pi.esign.mdb.StatusNotificationProcessor.onMessage(StatusNotificationProcessor.java:155)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jboss.as.ee.component.ManagedReferenceMethodInterceptor.processInvocation(ManagedReferenceMethodInterceptor.java:52)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.invocationmetrics.ExecutionTimeInterceptor.processInvocation(ExecutionTimeInterceptor.java:43)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:40)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
    at org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(ComponentDispatcherInterceptor.java:52)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.pool.PooledInstanceInterceptor.processInvocation(PooledInstanceInterceptor.java:51)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:255)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:334)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:240)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:47)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:100)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.deployment.processors.StartupAwaitInterceptor.processInvocation(StartupAwaitInterceptor.java:22)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory.processInvocation(ShutDownInterceptorFactory.java:64)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.deployment.processors.EjbSuspendInterceptor.processInvocation(EjbSuspendInterceptor.java:57)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:67)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponentDescription.processInvocation(MessageDrivenComponentDescription.java:239)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:60)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:438)
    at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:609)
    at org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:57)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
    at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:198)
    at org.jboss.as.ee.component.ViewDescription.processInvocation(ViewDescription.java:185)
    at org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:81)
    at com.hf.pi.esign.mdb.StatusNotificationProcessor$$$view2.onMessage(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jboss.as.ejb3.inflow.MessageEndpointInvocationHandler.doInvoke(MessageEndpointInvocationHandler.java:139)
    at org.jboss.as.ejb3.inflow.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:73)
    at com.hf.pi.esign.mdb.StatusNotificationProcessor$$$endpoint1.onMessage(Unknown Source)
    at com.ibm.mq.connector.inbound.MessageEndpointWrapper.onMessage(MessageEndpointWrapper.java:151)
    at com.ibm.mq.jms.MQSession$FacadeMessageListener.onMessage(MQSession.java:129)
    at com.ibm.msg.client.jms.internal.JmsSessionImpl.run(JmsSessionImpl.java:3250)
    at com.ibm.mq.jms.MQSession.run(MQSession.java:937)
    at com.ibm.mq.connector.inbound.ASFWorkImpl.doDelivery(ASFWorkImpl.java:104)
    at com.ibm.mq.connector.inbound.AbstractWorkImpl.run(AbstractWorkImpl.java:233)
    at org.jboss.jca.core.workmanager.WorkWrapper.runWork(WorkWrapper.java:445)
    at org.jboss.as.connector.services.workmanager.WildflyWorkWrapper.runWork(WildflyWorkWrapper.java:68)
    at org.jboss.jca.core.workmanager.WorkWrapper.run(WorkWrapper.java:223)
    at org.jboss.threads.SimpleDirectExecutor.execute(SimpleDirectExecutor.java:33)
    at org.jboss.threads.QueueExecutor.runTask(QueueExecutor.java:808)
    at org.jboss.threads.QueueExecutor.access0(QueueExecutor.java:45)
    at org.jboss.threads.QueueExecutor$Worker.run(QueueExecutor.java:828)
    at java.lang.Thread.run(Thread.java:748)
    at org.jboss.threads.JBossThread.run(JBossThread.java:320)
    ..
    ..
    ..
    ..
    Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DatabaseException
    Internal Exception: java.sql.SQLException: IJ031017: You cannot set autocommit during a managed transaction
    Error Code: 0
    Query: InsertObjectQuery(com.hf.pi.esign.dao.db.entity.OpportunityEntity@4753c567)
        at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicBeginTransaction(DatabaseAccessor.java:245)
    ..
    ..
        ... 103 more
    Caused by: java.sql.SQLException: IJ031017: You cannot set autocommit during a managed transaction
        at org.jboss.jca.adapters.jdbc.BaseWrapperManagedConnection.setJdbcAutoCommit(BaseWrapperManagedConnection.java:973)
        at org.jboss.jca.adapters.jdbc.WrappedConnection.setAutoCommit(WrappedConnection.java:787)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicBeginTransaction(DatabaseAccessor.java:238)
        ... 133 more

数据源配置为

<xa-datasource jndi-name="java:jboss/datasources/esign_cons_ds" pool-name="esign_cons_ds">
                    <xa-datasource-property name="URL">
                        jdbc:oracle:thin:@database:1521/ease.world
                    </xa-datasource-property>
                    <driver>oracle</driver>
                    <xa-pool>
                        <min-pool-size>1</min-pool-size>
                        <max-pool-size>15</max-pool-size>
                    </xa-pool>
                    <security>
                        <user-name>username</user-name>
                        <password>password</password>
                    </security>
                    <validation>
                        <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker"/>
                        <validate-on-match>true</validate-on-match>
                        <background-validation>false</background-validation>
                        <use-fast-fail>true</use-fast-fail>
                        <stale-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleStaleConnectionChecker"/>
                        <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter"/>
                    </validation>
                </xa-datasource>

JPA 在 PersistenceJPAConfig 中配置为

@Configuration
@Import(EnvironmentConfig.class)
@EnableTransactionManagement
public class PersistenceJPAConfig implements BeanFactoryAware{
    /** Logger*/
    private static final Log LOG = LogFactory.getLog(PersistenceJPAConfig.class);

    /** JNDI Name*/
    private static final String DATA_SOURCE_JNDI_NAME = "consumer.datasource.jndi.name";
    /** DAO Scan packages*/
    private static final String[] DAO_PACKAGE = { "com.hf.pi.esign.dao.*","com.hf.pi.esign.dao.db.entity.*" };
    /** beanFactory*/
    private BeanFactory beanFactory;
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
    private Environment getEnv(){
        return this.beanFactory.getBean(EnvironmentConfig.class).getEnv();
    }

    private String getDataSourceName(){
        String dataSourceName = getEnv().getProperty(DATA_SOURCE_JNDI_NAME);
        LOG.info("Consumer JPA config ressolved jndi name : "+dataSourceName);
        if(StringUtils.isEmpty(dataSourceName)){
            throw new IllegalStateException("Invalid data source name from property file "+DATA_SOURCE_JNDI_NAME);
        }
        return dataSourceName;
    }

    /**
     * EntityManager is set up by creating a Spring factory bean to manage it;
     * this will allow the PersistenceAnnotationBeanPostProcessor to retrieve it
     * from the Container.
     * 
     * @return
     */
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(DAO_PACKAGE);

        // Do not import Eclipse JPA Provider directly here
        // (org.eclipse.persistence.jpa.PersistenceProvider)
        // Using Spring Adapter for EclipseLink
        JpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);

        // JPA properties usually specified in persistence.xml file is imported
        // using below statement
        em.setJpaProperties(additionalProperties());

        return em;
    }

    @Bean
    public PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
        return new PersistenceAnnotationBeanPostProcessor();
    }

    @Bean
    public DataSource dataSource() {
        DataSource dataSource = null;

        try {
            InitialContext ctx = new InitialContext();
            dataSource = (DataSource) ctx.lookup(getDataSourceName());
        } catch (NamingException ne) {
            LOG.error(ne);
        }

        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();

        // set the EntityManagerFactory that this instance should manage
        // transactions for
        transactionManager.setEntityManagerFactory(this
                .entityManagerFactoryBean().getObject());
        return transactionManager;
    }


    private Properties additionalProperties() {
        Properties defaultProperties = new Properties();
        defaultProperties.put("eclipselink.logging.level", "false");
        try {
            LOG.info("loading eclipselink props");
            Resource resource = new ClassPathResource("/eclipselink.properties");
            defaultProperties = PropertiesLoaderUtils.loadProperties(resource);
            LOG.info("eclipselink:" + defaultProperties);
        } catch (IOException e) {
            LOG.error(e);
        }
        return defaultProperties;
    }

}

eclpipselink.properties

##This is EclipseLink Configuration File
eclipselink.logging.level=INFO

#enable weaving i.e. byte code instrumentation used by EclipseLink
eclipselink.weaving=false

#Caching Disabled as limitation of the shared cache, is that if the database
#is changed directly through JDBC, or by another application or server, 
#the objects in the shared cache will be stale
eclipselink.cache.shared.default=false

#performance related properties - for future optimization

#Optimization - avoid auto flush cost on query execution 
eclipselink.persistence-context.flush-mode=commit

#Optimization - close EntityManager on commit, to avoid cost of resume 
eclipselink.persistence-context.close-on-commit=true

#Optimization - avoid cost of persist on commit 
#eclipselink.persistence-context.persist-on-commit=false

我应该将下面的实现从 JPA 更改为 JTA 来解决这个问题吗?

@Bean
    public PlatformTransactionManager transactionManager() {

        // JtaTransactionManager.
        JpaTransactionManager transactionManager = new JpaTransactionManager();

        // set the EntityManagerFactory that this instance should manage
        // transactions for
        transactionManager.setEntityManagerFactory(this
                .entityManagerFactoryBean().getObject());
        return transactionManager;
    }

@Bean
    public PlatformTransactionManager transactionManager() {

        // JtaTransactionManager.
        JtaTransactionManager transactionManager = new JtaTransactionManager();


        return transactionManager;
    }

我们已将 JPATransactionManager 更改为 JTATransactionManager,并将 LocalEntityManager 中的数据源设置为 jtaDatasource 以解决问题。

public PlatformTransactionManager transactionManager() {

        // JtaTransactionManager.
        JtaTransactionManager transactionManager = new JtaTransactionManager();


        return transactionManager;
    }




@Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {

        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
            em.seJtatDataSource(dataSource());
...
...
}