TransactionRolledbackLocalException访问@Singleton时客户端的事务中止

Sne*_*kse 4 java jpa transactions ejb-3.1

注意:在花费的时间远远超过我想要找到原因的时间之后,以简短的形式添加这个问题.希望我能拯救别人一些痛苦.

将方法调用委托给带EJB注释的方法时@Singleton,容器会抛出一个Exception:

TransactionRolledbackLocalException Client's transaction aborted 
Run Code Online (Sandbox Code Playgroud)

Singleton bean没有数据访问.

ServiceBeanImpl.java

@Stateless
@Local
public class ServiceBean extends BaseBean{ 
  @EJB private CacheService cacheService;

  public FooObj getFooFromCache(int id) {
    FooObj fooObj = (FooObj) cacheService.get(id);
    if (fooObj == null) {
      fooObj = getEntityById(FooObj.class, id);
      cacheService.put(id, fooObj);  //This throws exception
    }
    return cacheService.get(id);
  }
}
Run Code Online (Sandbox Code Playgroud)

CacheServiceImpl.java

@Singleton
@Startup
public class CacheServiceImpl implements CacheService {
    private Cache cache;

    @PostConstruct
    public void init() {
        CacheManager instance = CacheManager.getInstance();
        cache = instance.getCache("cache");
    }

    @PreDestroy
    public void destroy() {
        CacheManager.getInstance().shutdown();
    }

    public Object get(Object id) {
      return cache.get(id);
    }

    public void put(Object id, Object obj) {
      return cache.put(id, obj);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题 为什么调用不进行数据访问的Singleton bean会抛出Transaction异常?

Sne*_*kse 6

简短回答: 检查先前执行的代码堆栈(假设StackTrace中没有线索),以获取被捕获但未传播的异常(因此StackTrace中没有线索).

在这个特殊情况下,有一个try/catch创建命名查询.如果该命名查询失败,则在catch块中执行辅助查询.查询不需要事务,因此回退查询正确执行并返回预期的实体.

然而...

这也(我认为)标志着交易需要回滚.该@Singletonbean是有些中,红鲱鱼.关于将控制权转移到该bean的事情使容器检查了Transaction,而Transaction又在那时抛出了异常,但由于事务不再有效,因此该异常是合适的.

故事的道德启示:

  • 向后工作到最后一次数据库交互,因为这可能是你的问题所在.
  • 仅仅因为最后一次数据库交互返回数据并不意味着它没有问题(这对我来说是杀手).