WildFly 14无状态Bean跨非XA数据源查询事务问题及禁用方案
解决WildFly 14中无状态Bean访问两个非XA数据库的事务问题
首先咱们拆解你遇到的两个核心问题,再给出针对性的解决方案:
为什么会存在事务?
EJB的@Stateless Bean默认事务属性是REQUIRED——也就是说,只要你调用这个Bean的方法,容器会自动帮你创建一个事务(如果当前没有事务上下文的话)。当你获取第一个数据库连接时,这个非XA连接就被绑定到了容器创建的事务中。此时再尝试获取第二个非XA连接,Arjuna事务管理器就会触发ARJUNA012140警告,因为它不允许同一个事务中存在多个非XA资源(这是为了避免分布式事务的一致性风险,非XA资源不支持两阶段提交)。
为什么@TransactionAttribute(NEVER)会报错?
NEVER注解的要求是调用方绝对不能带着事务上下文来调用这个方法。如果你的Bean是被另一个已经处于事务中的组件(比如另一个EJB、带事务的Servlet)调用,或者容器在某些场景下自动创建了事务上下文,就会触发WFLYEJB0063错误——因为它检测到了存在的事务,违反了NEVER的约束。
正确的解决方案:使用NOT_SUPPORTED事务属性
对于你的只读查询场景,最合适的事务属性是NOT_SUPPORTED。它的作用是:如果当前存在事务上下文,容器会先暂停这个事务,让你的方法在无事务环境下执行,方法完成后再恢复原来的事务。这样两个数据库连接都不会绑定到任何事务中,自然就不会触发Arjuna的多资源限制。
代码示例
修改你的无状态Bean,添加@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)注解(可以加在类上,也可以只加在需要的方法上):
import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.naming.InitialContext; import javax.sql.DataSource; import java.sql.*; @Stateless @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public class YourReadOnlyBean { public void executeDualQueries() throws Exception { // 访问第一个数据库 InitialContext context = new InitialContext(); DataSource ds = (DataSource) context.lookup("jndi/to/db/1"); try (Connection conn = ds.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("select * from table1")) { // 处理第一个结果集 while (rs.next()) { // 你的业务逻辑 } } // 访问第二个数据库 InitialContext context2 = new InitialContext(); DataSource ds2 = (DataSource) context2.lookup("jndi/to/db/2"); try (Connection conn2 = ds2.getConnection(); Statement stmt2 = conn2.createStatement(); ResultSet rs2 = stmt2.executeQuery("select * from table2")) { // 处理第二个结果集 while (rs2.next()) { // 你的业务逻辑 } } } }
额外提示
- 示例中用了try-with-resources语法,它会自动关闭
Connection、Statement和ResultSet,避免资源泄漏,建议你也使用这种方式。 - 确认你的两个数据源确实没有配置XA属性——因为如果是XA数据源,Arjuna会支持分布式事务,但你的只读场景完全没必要用XA,保持非XA即可。
内容的提问来源于stack exchange,提问作者ps0604
相关产品推荐
相关产品推荐

