无状态 EJB 的条件锁定方法

Conditionally locking method of a stateless EJB

无状态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 级别(但我不知道如何),它也不是一个完美的解决方案,因为当该方法 运行ning 与不同的组同时进行时,锁定是不必要的,并且会不必要地减慢系统速度。

其他解决方案是使用 @Lock(LockType.WRITE) 将该方法放入单例 EJB 中。但问题是一样的:对于不同的组,锁定是不必要的。

像这样可以解决问题:

public boolean DoCheckThanCreateAndAddItemToGroup(Item newItem, Group group) {
    lock(group) {
        // STEP 1

        // STEP 2
    }
}

如何在 EJB 环境中以合适的方式实现这种行为? (也许在分布式环境中也是如此。)

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

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

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

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

谢谢你,安德烈!