无状态EJB的方法必须在事务中执行读取和插入操作。第一步是复杂的检查,以测试是否允许使用给定参数进行插入操作。
public boolean DoCheckThanCreateAndAddItemToGroup(Item newItem, Group group) {
// STEP 1: checks if newItem can be created and added to group
// This is a complex operation with database reading and some logic
// using the current items of the group
if (!DoesNewItemFitInGroup(newItem, group)) {
return false;
}
// STEP 2: creates (persists) Item and adds it to Group
em.persist(newItem);
newItem.setGroup(group);
return true;
}
很明显,应该锁定整个方法以防止并发执行,以免在组中添加两个或多个不适合的项目。默认容器管理的JTA事务处理不提供此功能。该方法可以与同一组并行运行。
目前,当并行运行时,两个客户端都可以在任何进行插入操作之前通过检查,因此两个客户端都插入其新项目。但是这些项目在组中不合适:添加一个后,其他项目将无法通过检查,并且不能添加。
即使我可以将事务隔离设置为SERIALIZABLE级别(但我不知道如何),它也不是一个完美的解决方案,因为当该方法与不同的组同时运行时,锁定是不必要的并且会不必要地减慢系统速度。
其他解决方案是将方法放入带有@Lock(LockType.WRITE)的单例EJB中。但问题是一样的:对于不同的组锁定是不必要的。
这样的事情可以解决问题:
public boolean DoCheckThanCreateAndAddItemToGroup(Item newItem, Group group) {
lock(group) {
// STEP 1
// STEP 2
}
}
如何在EJB环境中以合适的方式实现此行为? (也许在分布式环境中。)
或者其他任何想法,如何正确处理这个问题?
答案 0 :(得分:0)
不知怎的,我想用组对象锁定方法。该解决方案基于Andrei的想法,但我没有必要修改Group实体。我只需要在无状态会话bean方法的开头添加这些行:
Group lockGroup = em.find(Group.class, group.getId());
em.lock(lockGroup, LockModeType.PESSIMISTIC_WRITE);
对实体对象的悲观锁定确保如果客户端已经锁定了相同的实体对象,则第二个客户端在em.lock行等待,直到第一个客户端提交整个事务。
谢谢你,Andrei!