Wildfly10运行原Weblogic正常的EJB代码报事务异常如何解决
故障根因
抛出javax.persistence.TransactionRequiredException的直接原因是:执行query.executeUpdate()更新操作时,当前线程未绑定活跃的JTA事务,而容器通过@PersistenceContext注入的是JTA类型的EntityManager,JPA规范要求该类型的持久化上下文执行写操作必须处于活跃事务中。
代码在Weblogic可运行、Wildfly 10报错,核心是两个应用服务器对Java EE规范的兼容策略差异:Weblogic提供了大量非标准的厂商容错特性,Wildfly 10则严格遵循Java EE 7规范要求,以下是按概率排序的具体诱因:
- 同EJB内部自调用未经过容器代理
Weblogic默认对EJB类做了字节码增强,即使是同个类内部通过this调用业务方法,也会走容器生成的代理对象,@TransactionAttribute声明的事务逻辑会正常生效;但Wildfly严格遵循EJB规范,自调用直接操作原始类实例,不会经过事务拦截器链,方法上标注的@TransactionAttribute(TransactionAttributeType.REQUIRED)完全不生效,不会自动开启事务。 - 自定义拦截器破坏事务上下文
代码中配置了LogInterceptor拦截器,如果拦截器的@AroundInvoke切面方法标注了@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)/NEVER,或者切面逻辑中没有在所有分支调用invocationContext.proceed()、手动吞掉异常提前返回,Weblogic会自动兜底补建事务上下文,Wildfly则会直接挂起或清空事务上下文,导致目标方法执行时无可用事务。 - 持久化单元配置不符合规范
如果persistence.xml中对应持久化单元配置了transaction-type="RESOURCE_LOCAL",Weblogic会自动兼容将其纳入容器JTA事务管理;但Wildfly严格区分JTA和RESOURCE_LOCAL两种持久化单元类型,RESOURCE_LOCAL类型的持久化单元必须手动通过em.getTransaction().begin()/commit()管理事务,容器不会为其自动开启JTA事务,执行写操作就会抛出异常。
排查修复方案
按优先级逐一验证修复:
- 修复自调用问题
禁止在EJB类内部通过this.clearStage()直接调用标注了事务注解的方法,两种可选修复方式:- 将
clearStage()方法拆分到独立的无状态EJB中,在当前类注入后调用; - 通过JNDI查找当前EJB的容器代理对象,再调用业务方法,示例代码:
InitialContext ctx = new InitialContext(); ActionPlanDao proxy = (ActionPlanDao) ctx.lookup("java:module/ActionPlanDaoImpl"); proxy.clearStage(); - 将
- 修复拦截器配置
- 移除
LogInterceptor中@AroundInvoke方法上的所有@TransactionAttribute注解,默认拦截器会继承目标方法的事务属性; - 检查拦截器逻辑,确保所有分支都会调用
invocationContext.proceed(),不要在拦截器中捕获异常后手动返回而不抛出,避免事务被意外标记回滚后上下文被清除。
- 移除
- 修正持久化单元配置
打开persistence.xml检查配置:- 容器通过
@PersistenceContext注入的持久化单元,必须显式配置transaction-type="JTA"; - 持久化单元必须绑定Wildfly中配置的JTA数据源,不要在JTA类型的持久化单元中配置本地JDBC连接参数。
- 容器通过
- 入口组件校验
如果调用ActionPlanDao的入口是Servlet、CDI Bean等组件,检查入口方法不要标注@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)挂起事务,也不要在调用EJB方法前手动提交/回滚了当前关联的UserTransaction。
内容的提问来源于stack exchange,提问作者kim
相关产品推荐
相关产品推荐

