注意:在花费的时间远远超过我想要找到原因的时候,用简短的形式添加这个问题。希望我能为别人带来一些痛苦。
将方法调用委托给注释为EJB
的{{1}}时,容器会抛出以下行的异常:
@Singleton
Singleton bean无法访问数据。
ServiceBeanImpl.java
TransactionRolledbackLocalException Client's transaction aborted
CacheServiceImpl.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);
}
}
问题 为什么调用不进行数据访问的Singleton bean会引发Transaction异常?
答案 0 :(得分:6)
简答: 检查先前执行的代码堆栈(假设StackTrace中没有线索),以获取被捕获但未传播的异常(因此StackTrace中没有线索)。
在这种特殊情况下,创建命名查询时出现try/catch
。如果该命名查询失败,则在catch块中执行辅助查询。查询不需要事务,因此回退查询正确执行并返回预期的实体。
...然而
那也(我认为)标志着交易需要回滚。 @Singleton
豆有点像红鲱鱼。关于将控制转移到该bean的事情使得容器检查了Transaction,而Transaction又在那时抛出了异常,但是由于事务不再有效,异常是合适的。
故事的道德:
答案 1 :(得分: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()
执行“findUserByName”查询。如果没有可用结果,则JPA会抛出NoResultException
。我在userExists()
内捕获了一个并返回false(“用户不存在”)。
由于NoResultException是一个RuntimeException,所以我在这里强制回滚,就像我刚刚学到的那样!
最简单的方法是避免调用getSingleResult()
。而不是我使用getResultList()
和setMaxResults(1)
。如果没有结果,那将只返回一个空List,因此没有异常,因此没有回滚tx。
克里斯
答案 2 :(得分:0)
我在GlassFish / Payara Server中遇到TransactionRolledbackLocalException
的类似问题。但这是由GlassFish / Payara中的错误引起的,没有任何内容回滚到我的应用程序中。重新启动域以对其进行修复,如下所述:javax.ejb.TransactionRolledbackLocalException (Glassfish 3 + JPA + EclipseLink)