无法使用Atomikos配置涉及ActiveMQ和嵌入式H2的分布式事务

无法使用Atomikos配置涉及ActiveMQ和嵌入式H2的分布式事务,activemq,spring-transactions,atomikos,Activemq,Spring Transactions,Atomikos,我正在尝试使用Atomikos作为SpringMVC应用程序中的底层JTA实现,在嵌入式H2DB和ActiveMQ上建立分布式事务。 我已经关注或访问了与我遇到的错误相关的web/stackoverflow上的几乎每个页面,但还没有找到答案 以下是配置的相关部分: @Autowired @Bean(name = "transactionManager") public PlatformTransactionManager getJtaTransactionManager(

我正在尝试使用Atomikos作为SpringMVC应用程序中的底层JTA实现,在嵌入式H2DB和ActiveMQ上建立分布式事务。 我已经关注或访问了与我遇到的错误相关的web/stackoverflow上的几乎每个页面,但还没有找到答案

以下是配置的相关部分:

    @Autowired
    @Bean(name = "transactionManager")
    public PlatformTransactionManager getJtaTransactionManager(TransactionManager usrTxMgr,
                                                             @Qualifier("AtomikosUserTransaction") UserTransaction usrTx) {
    return new JtaTransactionManager(usrTx, usrTxMgr);
}

@Autowired
@Bean(name = "transactionManager")
public PlatformTransactionManager getJtaTransactionManager(TransactionManager usrTxMgr,
                                                           @Qualifier("AtomikosUserTransaction") UserTransaction usrTx) {
    return new JtaTransactionManager(usrTx, usrTxMgr);
}

@Bean(name = "AtomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public TransactionManager getAtomikosTransactionManager() {
    return new UserTransactionManager();
}

@Bean(name = "AtomikosUserTransaction")
public UserTransaction getAtomikosUserTransaction() throws SystemException {
    UserTransactionImp usrTx = new UserTransactionImp();
    usrTx.setTransactionTimeout(30);
    return usrTx;
}

@Bean(name = "H2X")
public AtomikosDataSourceBean getXADataSource() {
    JdbcDataSource h2x = new JdbcDataSource();
    h2x.setURL("jdbc:h2:˜/test1" + ";" + "INIT=RUNSCRIPT FROM 'classpath:sql/create-db.sql'");
    h2x.setUser("sa");
    h2x.setPassword("");

    AtomikosDataSourceBean atkDs = new AtomikosDataSourceBean();
    atkDs.setXaDataSource(h2x);
    atkDs.setUniqueResourceName("AtomikosXADataSource");
    return atkDs;
}


@Autowired
@Bean(name = "H2TemplateX")
public NamedParameterJdbcTemplate getJdbcTemplateX(@Qualifier("H2X") AtomikosDataSourceBean atkDs) {
    return new NamedParameterJdbcTemplate(atkDs);
}

 @Bean(name = "ActiveMQXACF")
public ConnectionFactory getXAConnectionFactory(@Value("${brokerURL:tcp://localhost:61616}") String brokerURL) {
    ActiveMQXAConnectionFactory activeMQXAConnectionFactory = new org.apache.activemq.ActiveMQXAConnectionFactory(brokerURL);
    AtomikosConnectionFactoryBean atomikosJMSConnectionFactoryBean = new AtomikosConnectionFactoryBean();
    atomikosJMSConnectionFactoryBean.setUniqueResourceName("AtomikosJMSConnectionFactory");
    atomikosJMSConnectionFactoryBean.setXaConnectionFactory(activeMQXAConnectionFactory);

    return atomikosJMSConnectionFactoryBean;
}

@Bean(name = "JMSTemplateX")
public JmsTemplate getXAJMSTemplate(@Autowired @Qualifier("ActiveMQXACF") ConnectionFactory cf, @Value("${JMSDestination}") String destination) {
    JmsTemplate jt = new JmsTemplate();
    jt.setConnectionFactory(cf);
    jt.setDefaultDestinationName(destination);
    jt.setSessionTransacted(true);
    return jt;
}
这些是注释为@Transactional的方法。它们都位于不同的服务/存储库/组件类中

@Transactional
public void saveMessage(String message) {
    messageSaver.insertMessage(message);
    processor.processMessage(message);
}

@Transactional
public void processMessage(final String message){
    jmsTemplate.send("Queue1", new MessageCreator() {
        public Message createMessage(Session session) throws JMSException {
            return session.createTextMessage(message);
        }
    });
}

@Transactional
public void insertMessage(String msg) {
    if (msg.toLowerCase().contains("bad")) throw new RuntimeException("Can't  Commit to DB !!");
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("msg", msg);
    String sql = "insert into TBL_MESSAGE (message) values(:msg)";
    jdbcTemplateX.update(sql, params);
}
以下是Atomikos调试日志中的一些日志:

    DEBUG http-nio-8080-exec-1 com.atomikos.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'AtomikosXADataSource': getConnection()...
    INFO http-nio-8080-exec-1 com.atomikos.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'AtomikosXADataSource': init...
    WARN http-nio-8080-exec-1 com.atomikos.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'AtomikosXADataSource': poolSize equals default - this may cause performance problems!
    INFO http-nio-8080-exec-1 com.atomikos.jdbc.AtomikosDataSourceBean - AtomikosDataSoureBean 'AtomikosXADataSource': initializing with [ xaDataSourceClassName=null, uniqueResourceName=AtomikosXADataSource, maxPoolSize=1, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, testQuery=null, xaProperties=[], loginTimeout=0, maxLifetime=0]
    INFO http-nio-8080-exec-1 com.atomikos.datasource.xa.XATransactionalResource - AtomikosXADataSource: refreshed XAResource
    DEBUG http-nio-8080-exec-1 com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for conn5: url=jdbc:h2:˜/test1 user=SA: calling prepareStatement(insert into TBL_MESSAGE (message) values(?))...
    DEBUG http-nio-8080-exec-1 com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for conn5: url=jdbc:h2:˜/test1 user=SA: close()...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosConnectionFactoryBean - AtomikosConnectionFactoryBean 'AtomikosJMSConnectionFactory': createConnection()...
    INFO http-nio-8080-exec-1 com.atomikos.jms.AtomikosConnectionFactoryBean - AtomikosConnectionFactoryBean 'AtomikosJMSConnectionFactory': init...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosConnectionFactoryBean - AtomikosConnectionFactoryBean 'AtomikosJMSConnectionFactory': getReference()...
    INFO http-nio-8080-exec-1 com.atomikos.jms.AtomikosConnectionFactoryBean - AtomikosConnectionFactoryBean 'AtomikosJMSConnectionFactory': initializing with [ xaConnectionFactory=org.apache.activemq.ActiveMQXAConnectionFactory@59883d41, xaConnectionFactoryClassName=null, uniqueResourceName=AtomikosJMSConnectionFactory, maxPoolSize=1, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, xaProperties=[], localTransactionMode=false, maxLifetime=0, ignoreSessionTransactedFlag=true]
    INFO http-nio-8080-exec-1 com.atomikos.datasource.xa.XATransactionalResource - AtomikosJMSConnectionFactory: refreshed XAResource
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsConnectionProxy - atomikos connection proxy for resource AtomikosJMSConnectionFactory: creating XA-capable session...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsXaSessionProxy - atomikos xa session proxy for resource AtomikosJMSConnectionFactory: calling toString on JMS driver session...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsXaSessionProxy - atomikos xa session proxy for resource AtomikosJMSConnectionFactory: calling createQueue on JMS driver session...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsXaSessionProxy - atomikos xa session proxy for resource AtomikosJMSConnectionFactory: calling createProducer on JMS driver session ActiveMQSession {id=ID:IG11061-58249-1492635876500-5:2:2,started=false}
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsXaSessionProxy - atomikos xa session proxy for resource AtomikosJMSConnectionFactory: calling createTextMessage on JMS driver session...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsMessageProducerProxy - atomikos MessageProducer proxy for ActiveMQMessageProducer { value=ID:IG11061-58249-1492635876500-5:2:2:1 }: send ( message )...
    WARN http-nio-8080-exec-1 com.atomikos.jms.ConsumerProducerSupport - atomikos MessageProducer proxy for ActiveMQMessageProducer { value=ID:IG11061-58249-1492635876500-5:2:2:1 }: The JMS session you are using requires a JTA transaction context for the calling thread and none was found.
发送消息时出现的错误表明,应该在JTA事务的上下文中发送消息,我假设由于@Transactional注释的存在,该事务将在第一次方法调用时创建

我查看了产生错误的Atomikos类的源代码,但没有弄清楚太多。错误发生在enlist()方法中:

任何帮助都将不胜感激

此链接有助于:

引述: “这意味着您需要通过@Autowired bean直接调用带注释的方法,否则事务将永远不会启动。如果您在@Autowired bean上调用一个未注释的方法,而该@Autowired bean本身调用一个已注释的公共方法,则会忽略您的注释。这是因为Spring AOP仅在首次输入时检查注释“自动连线代码。”

我把@enableTransactionManager也放在了我的WebConfig类上,它成功了! 之前,@EnableTransactionManagement注释仅在我的一个RootConfig类上可用,以及 @在@Service方法和两个后续的@Repository方法上进行事务处理

我可能应该阅读更多关于如何设置Spring事务边界以及各种@Enable*注释如何在内部工作的内容

仍然不是很清楚,但它现在起作用了

希望它也能帮助别人

    DEBUG http-nio-8080-exec-1 com.atomikos.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'AtomikosXADataSource': getConnection()...
    INFO http-nio-8080-exec-1 com.atomikos.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'AtomikosXADataSource': init...
    WARN http-nio-8080-exec-1 com.atomikos.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'AtomikosXADataSource': poolSize equals default - this may cause performance problems!
    INFO http-nio-8080-exec-1 com.atomikos.jdbc.AtomikosDataSourceBean - AtomikosDataSoureBean 'AtomikosXADataSource': initializing with [ xaDataSourceClassName=null, uniqueResourceName=AtomikosXADataSource, maxPoolSize=1, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, testQuery=null, xaProperties=[], loginTimeout=0, maxLifetime=0]
    INFO http-nio-8080-exec-1 com.atomikos.datasource.xa.XATransactionalResource - AtomikosXADataSource: refreshed XAResource
    DEBUG http-nio-8080-exec-1 com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for conn5: url=jdbc:h2:˜/test1 user=SA: calling prepareStatement(insert into TBL_MESSAGE (message) values(?))...
    DEBUG http-nio-8080-exec-1 com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for conn5: url=jdbc:h2:˜/test1 user=SA: close()...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosConnectionFactoryBean - AtomikosConnectionFactoryBean 'AtomikosJMSConnectionFactory': createConnection()...
    INFO http-nio-8080-exec-1 com.atomikos.jms.AtomikosConnectionFactoryBean - AtomikosConnectionFactoryBean 'AtomikosJMSConnectionFactory': init...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosConnectionFactoryBean - AtomikosConnectionFactoryBean 'AtomikosJMSConnectionFactory': getReference()...
    INFO http-nio-8080-exec-1 com.atomikos.jms.AtomikosConnectionFactoryBean - AtomikosConnectionFactoryBean 'AtomikosJMSConnectionFactory': initializing with [ xaConnectionFactory=org.apache.activemq.ActiveMQXAConnectionFactory@59883d41, xaConnectionFactoryClassName=null, uniqueResourceName=AtomikosJMSConnectionFactory, maxPoolSize=1, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, xaProperties=[], localTransactionMode=false, maxLifetime=0, ignoreSessionTransactedFlag=true]
    INFO http-nio-8080-exec-1 com.atomikos.datasource.xa.XATransactionalResource - AtomikosJMSConnectionFactory: refreshed XAResource
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsConnectionProxy - atomikos connection proxy for resource AtomikosJMSConnectionFactory: creating XA-capable session...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsXaSessionProxy - atomikos xa session proxy for resource AtomikosJMSConnectionFactory: calling toString on JMS driver session...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsXaSessionProxy - atomikos xa session proxy for resource AtomikosJMSConnectionFactory: calling createQueue on JMS driver session...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsXaSessionProxy - atomikos xa session proxy for resource AtomikosJMSConnectionFactory: calling createProducer on JMS driver session ActiveMQSession {id=ID:IG11061-58249-1492635876500-5:2:2,started=false}
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsXaSessionProxy - atomikos xa session proxy for resource AtomikosJMSConnectionFactory: calling createTextMessage on JMS driver session...
    DEBUG http-nio-8080-exec-1 com.atomikos.jms.AtomikosJmsMessageProducerProxy - atomikos MessageProducer proxy for ActiveMQMessageProducer { value=ID:IG11061-58249-1492635876500-5:2:2:1 }: send ( message )...
    WARN http-nio-8080-exec-1 com.atomikos.jms.ConsumerProducerSupport - atomikos MessageProducer proxy for ActiveMQMessageProducer { value=ID:IG11061-58249-1492635876500-5:2:2:1 }: The JMS session you are using requires a JTA transaction context for the calling thread and none was found.
   protected void enlist() throws JMSException {
    CompositeTransaction ct = null;
    CompositeTransactionManager ctm = this.getCompositeTransactionManager();
    boolean enlist = false;
    if(ctm != null) {
        ct = ctm.getCompositeTransaction();
        if(ct != null && ct.getProperty("com.atomikos.icatch.jta.transaction") != null) {
            enlist = true;
        }
    }

    if(enlist) {
        this.registerSynchronization(ct);

        try {
            this.state.notifyBeforeUse(ct);
        } catch (InvalidSessionHandleStateException var6) {
            String msg1 = "error during enlist: " + var6.getMessage();
            LOGGER.logWarning(this + ": " + msg1);
            AtomikosJMSException.throwAtomikosJMSException(msg1, var6);
        }
    } else {
        String msg = "The JMS session you are using requires a JTA transaction context for the calling thread and none was found.\nPlease correct your code to do one of the following: \n1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or\n2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or\n3. create a non-transacted session and do session acknowledgment yourself, or\n4. set localTransactionMode to true so connection-level commit/rollback are enabled.";
        LOGGER.logWarning(this + ": " + msg);
        AtomikosTransactionRequiredJMSException.throwAtomikosTransactionRequiredJMSException(msg);
    }