5

注意:在花费了比我想承认的更多的时间来寻找原因之后,以简短的形式添加这个问题并给出答案。希望我能减轻别人的痛苦。

将方法调用委托给带有EJB注释的方法时@Singleton,容器会抛出异常,如下所示:

TransactionRolledbackLocalException Client's transaction aborted 

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);
  }
}

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);
    }
}

问题 为什么调用没有数据访问的 Singleton bean 会引发 Transaction 异常?

4

3 回答 3

7

简短的回答: 检查之前执行的代码堆栈(假设 StackTrace 中没有线索)是否存在被捕获且未传播的异常(因此 StackTrace 中没有线索)。

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

然而...

这也(我认为)将事务标记为需要回滚。@Singleton豆子有点像红鲱鱼。关于将控制权转移到该 bean 的某些事情使容器检查了事务,这反过来又在此时抛出了异常,但由于事务不再有效,因此该异常是适当的。

故事的道德启示:

  • 回到最后的数据库交互,因为那可能是你的问题所在。
  • 仅仅因为最后一次数据库交互返回数据并不意味着它没有问题(这对我来说是杀手)。
于 2012-10-18T06:06:31.077 回答
2

我遇到了类似的问题,发现了一个有趣的事情:

从@Startup @Singleton 我有以下电话

@PostConstruct
public void initHardcodedUsers() {
for (User u : getHardcodedUsers()) {
  if (!userRepository.userExists(u.getName())) {
    userRepository.add(u);
  }
 }
}

UserRepository 是一个带有 EntityManager 的 @Stateless EJB。在userExists()方法中,我基本上使用getSingleResult(). 如果没有可用的结果,NoResultException则 JPA 会抛出 a。我在里面抓住那个userExists()并返回错误(“用户不存在”)。

正如我刚刚了解到的,由于 NoResultException 是 RuntimeException ,所以这里强制回滚!

最简单的方法是避免调用getSingleResult(). 而不是我使用getResultList()and setMaxResults(1)。如果没有结果,这将简单地返回一个空列表,因此没有异常,因此没有回滚 tx。

祝你好运 :)

克里斯

于 2014-01-17T07:33:40.197 回答
2

GlassFish / Payara Server 中的类似问题TransactionRolledbackLocalException发生在我身上。但它是由 GlassFish / Payara 中的错误引起的,在我的应用程序中没有回滚事务。重新启动域修复它,如下所述:javax.ejb.TransactionRolledbackLocalException (Glassfish 3 + JPA + EclipseLink)

于 2018-08-06T22:59:28.697 回答