条件锁定无状态EJB的方法

时间:2015-11-19 14:38:16

标签: java-ee concurrency locking stateless-session-bean transaction-isolation

无状态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环境中以合适的方式实现此行为? (也许在分布式环境中。)

或者其他任何想法,如何正确处理这个问题?

1 个答案:

答案 0 :(得分:0)

不知怎的,我想用组对象锁定方法。该解决方案基于Andrei的想法,但我没有必要修改Group实体。我只需要在无状态会话bean方法的开头添加这些行:

Group lockGroup = em.find(Group.class, group.getId());
em.lock(lockGroup, LockModeType.PESSIMISTIC_WRITE);

对实体对象的悲观锁定确保如果客户端已经锁定了相同的实体对象,则第二个客户端在em.lock行等待,直到第一个客户端提交整个事务。

谢谢你,Andrei!

相关问题