WAR多数据源问题:容器事务失败Bean事务正常的原因
WildFly 10中Bean事务管理可行的原因及与容器事务的区别
这个问题我太熟悉了——你碰到的是JTA事务管理器(Arjuna)对多Non-XA数据源的限制,而Bean事务管理(BMT)刚好绕开了这个坑,所以能正常跑起来。下面给你掰扯清楚:
一、为啥Bean事务管理(BMT)能正常运行?
你用的是两个Non-XA数据源,默认的容器事务管理(CMT)会把这两个EJB的数据库操作塞进同一个JTA全局事务里。但JTA规范有个严格限制:一个全局事务最多只能包含一个Non-XA资源(WildFly的Arjuna默认严格执行这个规则,不允许多个Non-XA资源混在一个全局事务里),这就导致Arjuna报错说“不能添加多个最后资源”,最终连JDBC连接都拿不到。
而BMT模式下,你完全掌控事务的边界:
- 你可以给第一个数据源的操作单独开一个事务,执行完提交/回滚后,再开第二个事务处理第二个数据源的操作
- 甚至可以不给这些操作加全局事务,让每个EJB的数据库操作使用各自的本地事务
这样两个数据源的操作不在同一个全局事务里,Arjuna就不会跳出来拦着,自然能正常获取连接了。
二、容器事务管理(CMT)和Bean事务管理(BMT)的核心区别
1. 事务控制权归属
- CMT:事务的创建、提交、回滚全由WildFly容器说了算。你只需要用
@TransactionAttribute注解指定事务属性(比如默认的Required),容器会自动帮你处理事务的开始和结束。 - BMT:事务的生命周期完全由你的代码控制。你得通过
UserTransaction接口手动调用begin()、commit()、rollback()方法,什么时候开事务、什么时候提交全看你写的代码逻辑。
2. 事务范围处理逻辑
- CMT:默认情况下,同一个调用链里的所有数据库操作都会被纳入同一个全局事务(比如你调用两个不同数据源的EJB,容器会尝试把这两个Non-XA资源都加进同一个JTA事务),这就触发了Arjuna的限制,直接报错。
- BMT:你可以灵活拆分事务范围,比如让两个数据源的操作分别在独立的事务里执行,或者干脆不用全局事务,完美避开多Non-XA资源的冲突问题。
3. 适用场景差异
- CMT:适合大多数常规业务场景,不用自己写事务管理代码,容器帮你搞定一致性,减少冗余代码。
- BMT:适合需要精细控制事务的场景,比如跨多个Non-XA数据源的操作、或者需要在事务里调用外部服务后再决定是否提交的情况。
你的场景代码示例
@Stateless public class TestEjb { @Inject private EspacioManager espacioMgr; @Inject private ServeiManager serveiMgr; public void test() { Espacio espacioBase = espacioMgr.findByCodEspai(1); // 对应OracleDS(Non-XA) Servei servei = serveiMgr.findById(1); // 对应MySqlDS(Non-XA) // 此处触发Arjuna报错 } }
报错信息
Arjuna提示不允许添加多个最后资源,无法将资源纳入事务,最终导致无法获取JDBC连接。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

