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

Tin*_*Sky 5 java jpa

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

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

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

我只是通过创建一个具有上述同步方法的单例管理器类来解决这个问题。

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

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

chr*_*ke- 6

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


Yog*_*esh 5

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

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

您需要在列值上创建约束以进行简单的数据验证,例如not null或unique等。对于复杂的情况,我所做的是在数据库表上创建一个触发器,该触发器检查正在插入或更新的值,如果它违反了它的条件将甚至设置一条消息,该消息将提供失败的原因,您可以在 Java 代码中处理这些异常,以便向用户发送适当的消息。为此,您将需要对此知之甚少,如果您不知道,学习和实施它并不难。在这里看看这个问题,有一些类似的背景。SIGNAL SQLSTATEPL/SQL

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