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



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

  • 从客户端获取param1
  • 创建对象x(新对象x(param1))
  • 检查数据库中是否存在对象x(jpa选择查询)
  • 如果不存在,则添加对象x(jpa存储实体)
  • 添加y(jpa存储实体)

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

我只是通过创建一个带有同步方法的singleton管理器类来解决这个问题,该方法完成了上述操作。

工作得很好,因为现在函数一次只能由一个客户端调用。(但当有2台服务器时,我确实遇到了问题,但现在还不是这样)

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

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

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

  1. 在Java中,你越是试图对数据一致性进行实时检查,你就越会扼杀代码。例如,如果可以访问特定表中更改数据的操作一开始是固定的,但随着应用程序的扩展可能会增加,那么跟踪单个操作方法中的所有检查将变得越来越麻烦。每次在应用程序中添加需要更改数据一致性检查方式的新操作时,您都必须检查该更改是否在级别上正确级联
  2. synchronized的使用会影响应用程序的性能,因为用户在其他用户执行操作时必须排队等候,我确信这在任何情况下都是不可接受的
  3. 如果有多个应用程序实例在同一服务器或多个服务器上运行,则几乎不可能在逻辑级别上进行此检查。或者在许多情况下,两个完全不同的应用程序试图更新同一数据库

您需要的是对列值创建约束,以进行简单的数据验证,例如not nullunique等。对于复杂的情况,我所做的是在数据库表上创建一个触发器,该触发器检查正在插入或更新的值,如果违反条件,它将SIGNALSQLSTATE,甚至设置一条消息,提供失败原因,您可以在Java代码中处理这些异常,以便向用户发送适当的消息。为此,你需要对PL/SQL有一点了解,如果你不了解的话,学习和实现它并不是那么困难。

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

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

最新更新