Java EE 8异步观察者无事务问题求助(CDI 2.0)
解决WildFly 12中CDI异步事件观察者的事务问题
我来帮你搞定这个WildFly里异步事件+事务的问题,我之前在Java EE 8环境里也踩过类似的坑,咱们一步步捋清楚。
为啥会出问题?
CDI 2.0的@ObservesAsync方法是跑在容器新开的独立线程里的,默认不会继承触发事件时的JTA事务上下文。而你的仓库标了@Transactional,它默认需要一个活跃的JTA事务才能正常工作——如果当前线程没事务,要么仓库会尝试自己开新事务(看传播属性),要么直接抛事务异常,这就是你遇到问题的根源。
具体解决办法
1. 给异步观察者方法加@Transactional注解
既然异步观察者本身没事务,直接给它标@Transactional,让容器为它启动一个新的JTA事务:
@ApplicationScoped public class AsyncEventListener { @Inject private YourTransactionalRepository repo; @Transactional // 给观察者方法加事务注解,确保整个逻辑在事务里跑 public void handleAsyncEvent(@ObservesAsync YourEvent event) { // 处理元数据 String metadata = event.getMetadata(); // 调用仓库操作数据库 repo.doDatabaseOperation(metadata); } }
这样整个观察者方法的逻辑都会在一个JTA事务里执行,仓库的@Transactional(默认传播属性是REQUIRED)会复用这个事务,不会出现无事务或者事务嵌套的问题。
2. 调整仓库的事务传播属性(按需)
如果你的仓库方法需要独立的事务(比如不管当前有没有事务都开新的),可以修改仓库的注解:
@Transactional(Transactional.TxType.REQUIRES_NEW) public class YourTransactionalRepository { public void doDatabaseOperation(String data) { // 这里写JDBC或JPA的数据库操作 } }
不过这个要谨慎用,REQUIRES_NEW会挂起当前事务(如果有的话)开新事务,适合必须独立的场景,比如日志记录这类不想影响主事务的操作。
3. 确认WildFly的配置没问题
WildFly 12对CDI 2.0异步事件是默认支持的,但要确保你的beans.xml是Java EE 8的正确配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" version="2.0" bean-discovery-mode="all"> </beans>
另外检查下WildFly的事务子系统配置,默认的standalone.xml里urn:jboss:domain:transactions部分是正常开启的,要是你改过配置,得确认没禁用事务功能。
踩坑提醒
- 别指望异步观察者能继承原事件的事务:异步线程和触发事件的线程完全隔离,原事务提交/回滚后,异步观察者拿不到任何上下文。
- 别在异步观察者里搞长事务:如果逻辑耗时久,事务会一直占着数据库连接,容易把连接池耗干,必要时可以拆分逻辑,或者用
@AsynchronousEJB配合事务来做。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

