如何使用JPA / Hibernate避免“双重创建”竞争条件

时间:2012-06-13 03:31:32

标签: hibernate jpa transaction-isolation

我遇到以下情况。

有几个线程可以读取/更新MonthlySales持久对象。问题是这些对象可能不存在,必须根据请求动态创建 因此,两个不同的线程最终创建对应于相同密钥的实体(即具有相同的ID),因此其中一个未能提交。我不希望这种情况发生。我希望两个线程中的一个赢得比赛而另一个线程松开,等待对象被另一个创建。

换句话说,我确实想做序列化交易。我应该使用显式Java锁(即synchronized块)吗?

我目前的代码如下:

MonthlySales ms = entityManager.find(MonthlySales.class, somekey);
if (ms == null) { // two threads might enter this block altogether
    ms = new MonthlySales();
    // prepare ms object populating its fields with default values
    entityManager.persist(ms);
    entityManager.flush();
}
entityManager.lock(ms, LockModeType.PESSIMISTIC_WRITE); // lock this object
                                                        // since we are going to update it
// do something with ms object
entityManager.getTransaction().commit();
entityManager.close();

你能帮助我吗?

1 个答案:

答案 0 :(得分:1)

避免竞争条件的一种方法是让具有最低ID的线程/进程/等获胜。

我相信你可以使用

访问线程ID
long threadID = Thread.currentThread().getId();

来自Java中的线程。这是比阻塞其他线程更好的竞争条件解决方案,因为这会破坏使用多个线程的目的。

参见Critical-Section Bakery算法:

http://www.basicsofcomputer.com/critical_section_problem_in_operating_system.htm

对于JPA,根据herehere,最佳实践方法似乎是尝试同时修改内容,并在事情无法解决时捕获异常。