【问题标题】:How to avoid "double-create" race condition using JPA/Hibernate如何使用 JPA/Hibernate 避免“双重创建”竞争条件
【发布时间】:2012-06-13 03:31:32
【问题描述】:

我处于以下情况。

有几个线程可以读取/更新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();

你能帮帮我吗?

【问题讨论】:

标签: hibernate jpa transaction-isolation


【解决方案1】:

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

我相信您可以使用

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

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

查看关键部分烘焙算法:

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

对于 JPA,根据herehere 的说法,最佳实践方法似乎是尝试同时修改事物,并在事情不成功时捕获异常。

【讨论】:

  • 这是一个“手工制作”的解决方案,我需要一个面向 JPA 的最佳实践。此外,阻塞线程不会破坏拥有多个线程的目的:它称为同步。最后,最低 id-win 解决方案已被弃用,因为它会导致一些线程饿死。现在我们有复杂的算法来管理尊重公平概念的同步。
  • 我记得操作系统类中专门解决了这个问题。我相信解决方案是让每个进程或在这种情况下的线程,像在快餐店中那样获取“票”或“数字”以进入关键部分。然后你会让编号最小的线程先行。在它离开临界区后,如果它想重新进入它必须取一个新的数字。这应该保持公平并防止饥饿。我添加了指向我的答案的链接。
  • 好的,看,我很欣赏你的努力,但我们不是在这里用汇编程序编写操作系统。 :) 我正在寻找 Java 问题的 Java 解决方案,它必须是最抽象和最高级的东西。我对低级、不可重用的解决方案不感兴趣。但是,我的问题的解决方案是通过显式同步来序列化事务。见:stackoverflow.com/questions/2992463/…
  • 我只是想提供低级解决方案,以防您必须自己实现它,但是当我发布最后一条评论时,我确实将该链接添加到我的答案中。
猜你喜欢
  • 1970-01-01
  • 2015-06-16
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多