简体   繁体   English

JMS不回滚XA事务(或不参与一个)

[英]JMS doesn't rollback XA transaction (or doesn't participate in one)

I'm relatively new to XA transactions. 我对XA交易比较陌生。 I've been struggling a few days to make a simple XA transaction work to no avail. 我几天都在努力使一个简单的XA交易工作无济于事。

First, I tried to use two different databases. 首先,我尝试使用两个不同的数据库。 I set up 2 XA datasources and had succeeded in rolling back the first database operation when the second fails. 我设置了2个XA数据源,并在第二个数据库操作失败时成功回滚了第一个数据库操作。 So far, so good. 到现在为止还挺好。 But then I tried to replace second datasource with JMS connectionFactory and cannot reproduce the same behavior. 但后来我尝试用JMS connectionFactory替换第二个数据源,并且无法重现相同的行为。

Here's the relevant code: 这是相关的代码:

Database logic : 数据库逻辑

@Stateless
public class FirstDB implements FirstDBLocal {

    @PersistenceContext(unitName = "xaunit")
    private EntityManager em;

    public void doSomething() {
        SomeEntity someEntity = em.find(SomeEntity.class, 1234L);
        someEntity.setSomeFlag(false);
    }

}

JMS code : JMS代码

@Stateless
public class SecondJMS implements SecondJMSLocal {

    @Resource(mappedName = "java:/JmsXA")
    private ConnectionFactory connFactory;

    @Resource(mappedName = "queue/Some.Queue")
    private Queue q;

    @Override
    @TransactionAttribute(TransactionAttributeType.MANDATORY)
    public void sendMsg() {
        Session session = null;
        Connection conn = null;
        MessageProducer producer = null;
        try {
            conn = connFactory.createConnection("guest", "guest");

            session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

            producer = session.createProducer(q);

            // Not sure if I need this, but I found it in the sample code
            conn.start();

            TextMessage tm = session.createTextMessage(new Date().toString());
            producer.send(tm);

            throw new RuntimeException("Fake exception");
        } catch (JMSException e) {
            e.printStackTrace();
        } catch (RuntimeException e) {
            e.printStackTrace();
        } finally {
            // close all resources
        }
    }

}

The glue code : 胶水代码

@Stateless
public class TestDBandJMS implements TestDBandJMSLocal {

    @EJB
    private FirstDBLocal firstDBLocal;

    @EJB
    private SecondJMSLocal secondJMSLocal;

    public void doStuff() {
        firstDBLocal.doSomething();
        secondJMSLocal.sendMsg();
    }

}

XA Connection Factory configuration (everything is JBoss default, except for commented out security settings): XA连接工厂配置 (除了注释掉的安全设置外,一切都是JBoss默认设置):

<tx-connection-factory>
      <jndi-name>JmsXA</jndi-name>
      <xa-transaction/>
      <rar-name>jms-ra.rar</rar-name>
      <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
      <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
      <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/DefaultJMSProvider</config-property>
      <max-pool-size>20</max-pool-size>
      <!-- <security-domain-and-application>JmsXARealm</security-domain-and-application> -->
      <depends>jboss.messaging:service=ServerPeer</depends>
   </tx-connection-factory>

I also have very simple MDB which just prints out received message to console (not going to post the code, since it's trivial). 我也有非常简单的MDB,只是将收到的消息输出到控制台(不会发布代码,因为它是微不足道的)。

The problem is, when the exception is thrown in JMS code, the message is still received by MDB and SomeEntity is successfully updated in the database code (whereas I expect it to rollback). 问题是,当在JMS代码中抛出异常时,MDB仍然会收到消息,并且在数据库代码中成功更新了SomeEntity(而我希望它能够回滚)。

Here is the JMS log . 这是JMS日志 One fishy thing that I see there is this: 我看到的一个可疑的事情就是:

received ONE_PHASE_COMMIT request

Like I said, I'm not too familiar with XA yet, but I expect to see here TWO_PHASE_COMMIT, because there should be 2 resources which participate in the active transaction. 就像我说的那样,我对XA还不太熟悉,但我希望在这里看到TWO_PHASE_COMMIT,因为应该有2个参与活动事务的资源。

Any help would be much appreciated. 任何帮助将非常感激。

UPDATE UPDATE

It worked eventually, after I tried @djmorton's suggestion. 在我尝试了@ djmorton的建议后,它最终起作用了。 One other important thing to keep in mind when working with JBoss 5.1 is that the lookup name for XA JMS ConnectionFactory is "java:/JmsXA". 使用JBoss 5.1时要记住的另一个重要事项是XA JMS ConnectionFactory的查找名称是“java:/ JmsXA”。 I tried the same with 我试过同样的

@Resource(mappedName = "XAConnectionFactory")
private ConnectionFactory connFactory;

and it didn't work. 它不起作用。

You are catching your RuntimeException after throwing it in your sendMsg() method. 将其抛入sendMsg()方法后,您将捕获RuntimeException。 The Exception will not trigger a transaction rollback unless it is thrown up the stack. 除非它被抛出堆栈,否则Exception不会触发事务回滚。 When using Container managed transactions, the container adds interceptors to the method calls to setup the transactions and handle rollbacks when unchecked exceptions are thrown. 使用Container托管事务时,容器会向方法调用添加拦截器,以便在抛出未经检查的异常时设置事务并处理回滚。 If the exception isn't thrown out of the method the interceptor doesn't know it needs to role the transaction back. 如果未从方法中抛出异常,则拦截器不知道它需要将事务作用回来。

Edit 1: 编辑1:

Note that only a RuntimeException or a subclass of RuntimeException being thrown will cause the transaction to rollback. 请注意,只抛出RuntimeException或RuntimeException的子类将导致事务回滚。 A checked exception (One that extends Exception rather than RuntimeException) will not cause a rollback unless it is annotated with @ApplicationException(rollback=true). 检查异常(扩展Exception而不是RuntimeException)将不会导致回滚,除非使用@ApplicationException(rollback = true)进行批注。

The other alternative is to inject an EJBContext object, and call .setRollbackOnly() to force the transaction to rollback when the method goes out of scope: 另一种方法是注入EJBContext对象,并调用.setRollbackOnly()以在方法超出范围时强制事务回滚:

@Stateless
public class SomeEjb {    
    @Resource
    private EJBContext context;

    @TransactionAttribute(TransactionAttributeType.MANDATORY)
    public void rollMeBack() {
        context.setRollbackOnly();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM