JPA多线程添加如果不存在?

时间:2014-02-13 13:34:17

标签: java jpa

我有一个服务器功能,许多客户端都会同时调用它。服务器功能执行以下操作:

  • 从客户
  • 获取param1
  • 创建对象x(新对象x(param1))
  • 检查对象x是否存在于db(jpa select query)
  • 如果不存在则添加对象x(jpa商店实体)
  • 添加y(jpa商店实体)

当两个或多个客户端同时运行该函数时会出错,多个x对象被添加到数据库中。

我只是通过使用同步方法创建一个单例管理器类来解决这个问题。

很好地工作,因为现在该功能一次只能由一个客户端调用。 (但是当有2台服务器时我确实遇到了问题,但事实并非如此)

但我想知道有更好的方法用jpa解决这个问题吗?

3 个答案:

答案 0 :(得分:3)

是的,整个操作应该在事务中执行,例如由JTA或Spring的@Transactional提供。如果事务被隔离在适当的级别(对于这种情况,我认为REPEATABLE_READ),底层持久性系统将确保不会发生冲突写入,通过阻塞一个事务直到另一个事务完成(基本上是{ {1}}在Java中执行,或者在检测到冲突时停止并回滚第二个事务(然后可以重试)。

答案 1 :(得分:3)

我能想到的唯一万无一失的解决方案是创建数据库级约束。这是因为

  1. 您尝试更多地实时检查数据在Java中的一致性,您将更多地扼杀代码。例如,如果能够访问特定表中的更改数据的操作在开始时是固定的,但随着应用程序的扩展而增加,则跟踪各个操作方法中的所有检查将变得越来越麻烦。每次在应用程序中添加需要更改的新操作时,都需要检查数据一致性是否正确,您必须检查该更改是否在级别上正确级联。
  2. 使用synchronized会影响应用程序性能,因为用户必须在其他用户执行操作时排队等候,我相信在任何情况下都不会接受这种情况。
  3. 如果在同一服务器或多个服务器上运行多个应用程序实例,则几乎不可能在逻辑级别上保持此检查。或者在许多情况下,两个完全不同的应用程序试图更新相同的数据库。
  4. 您需要为列值创建约束以进行简单数据验证,例如not nullunique等等。对于复杂情况,我所做的是在数据库表上创建一个检查值的触发器正在插入或更新的内容,如果它违反了条件,它将SIGNAL SQLSTATE甚至设置一条消息,提供失败原因,您可以在Java代码中处理这些异常,以便向用户发送相应的消息。为此,你需要对PL/SQL知之甚少,如果你不了解它并不难以学习和实现它。看看这个问题here和一些类似的背景。

    现在某些情况下,如果您使用的数据库不支持,例如,您无法直接创建数据库级别约束。几乎所有NoSQL个数据库,如果数据库为MySQL且表格的引擎为MyISAM等,那么在这些情况下你所能做的就是使用某些write commit锁定通过多个应用程序实例之间的一些常见应用程序代我没有在这种情况下试图找到适当的解决办法,因为这种情况很少发生。

答案 2 :(得分:0)

这里有人回答了类似的问题(Double Checked Locking in Singleton),解决方法是双重检查锁定单例。我要做的一个小调整是我不会创建对象x,而是在数据库中搜索值为== param1(如果可行)的行。