我对 XA 交易比较陌生。几天来,我一直在努力使一个简单的 XA 事务工作无济于事。
首先,我尝试使用两个不同的数据库。我设置了 2 个 XA 数据源,并在第二个数据库操作失败时成功回滚了第一个数据库操作。到现在为止还挺好。但是后来我尝试用 JMS connectionFactory 替换第二个数据源并且无法重现相同的行为。
以下是相关代码:
数据库逻辑:
@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 代码:
@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
}
}
}
胶水代码:
@Stateless
public class TestDBandJMS implements TestDBandJMSLocal {
@EJB
private FirstDBLocal firstDBLocal;
@EJB
private SecondJMSLocal secondJMSLocal;
public void doStuff() {
firstDBLocal.doSomething();
secondJMSLocal.sendMsg();
}
}
XA Connection Factory 配置(一切都是 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>
我也有非常简单的 MDB,它只是将收到的消息打印到控制台(不打算发布代码,因为它很简单)。
问题是,当 JMS 代码中引发异常时,MDB 仍会收到消息,并且 SomeEntity 已在数据库代码中成功更新(而我希望它回滚)。
这是JMS 日志。我在那里看到的一件可疑的事情是:
received ONE_PHASE_COMMIT request
就像我说的,我对 XA 还不太熟悉,但我希望在这里看到 TWO_PHASE_COMMIT,因为应该有 2 个资源参与活动事务。
任何帮助将非常感激。
更新
在我尝试了@djmorton 的建议后,它最终奏效了。使用 JBoss 5.1 时要记住的另一件重要事情是 XA JMS 的查找名称ConnectionFactory
是“java:/JmsXA”。我也试过了
@Resource(mappedName = "XAConnectionFactory")
private ConnectionFactory connFactory;
它没有用。