我的用例是 1..N 关系中的两个实体,比方说 Box 和 Items in Box。 Box 有一个属性“capacity”,它指定了我可以在 Box 中拥有多少 Items。
我实际上在做什么。我选择了 Box 中所有 Items 的计数,当 Items 的数量小于 Box.capacity 时,我保留了 Item。
问题是当我同时访问我的方法时。同时调用方法两次将导致读取可以并发运行,当进入写入阶段时,两个线程都将 Item 写入数据库。
我的代码:
@Entity
public class Box {
private int capacity;
}
@Entity
public class Item {
@ManyToOne
Box box;
}
@Stateless
public class BoxManager {
@PersistenceContext
EntityManager em;
public Item persistItem(Item item) {
Box box = item.getBox();
Query query = em.createQuery("SELECT COUNT(i) FROM Item i WHERE i.box = :box");
query.setParameter("box", box);
int itemCount = ((Number)typedQuery.getSingleResult()).intValue();
// We can simulate concurrent problem putting Thread.sleep() here.
if (itemCount < box.getCapacity()) {
return em.persist(item);
} else {
return null;
}
}
}
我正在同时调用方法 persistItem
。
问题是如何防止另一个线程在第一个线程持久化第一个项目之前读取错误数量的项目?
有问题的场景是:
Thread 1: Reads count of items
Thread 2: Reads count of items
Thread 1: Writes Item to database
Thread 2: Also Writes Item to database
或者有更好的方法来处理这个问题吗?如何在没有并发问题的情况下检查实体的数量并将其持久化?
最佳答案
使用 JPA,您可以添加锁定机制,从 2.0 版本开始,您就支持乐观和悲观锁定,在乐观版本中,您可以添加一个版本列,以检查实体的正确版本是否正在更改,在其他版本中hand 悲观锁使用数据库锁定语句。在您的情况下,您可以使用 Query.setLockMode
在查询中设置一个 block 。
在此article你可以获得更多信息
关于java - JPA:读取并坚持一个事务,同时阻塞不同线程中的读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20774930/