【问题标题】:How to prevent duplicate entries being created in database in quick succession? (JPA)如何防止在数据库中快速连续创建重复条目? (JPA)
【发布时间】:2014-02-19 14:35:54
【问题描述】:

我有一个项目,用户将 JSON 发布到我的 API,然后将其反序列化为实体并保存到数据库。 由于运行了一个负载测试工具,它快速连续发布许多请求(使用相同的 API 密钥,但作为不同的“用户”),我发现我的一些实体在数据库中重复。

虽然我的代码检查对象是否已存在于数据库中,但一些请求同时触发的速度太快,它们绕过了检查。

使用实体管理器,我认为每个请求都在其自己的事务下,但我不确定如何“锁定”这些事务。除了将创建代码放在通用 java 同步块中之外,还有什么方法可以防止这种重复?

谢谢。

【问题讨论】:

  • 你是如何将记录插入数据库的?,em.persist?,@Id 已设置?,这是你的数据库?

标签: java jakarta-ee jpa transactions


【解决方案1】:

如果您使用的是关系数据库 (I.E. SQL),那么最简单的方法是让数据库为您完成。你和数据库表的唯一约束:

CREATE UNIQUE INDEX unique_author_name ON authors (first_name, last_name);

上面的例子有一个名为“authors”的数据库表。每个作者都有名字和姓氏。该约束阻止数据库存储 2 个“马克吐温”。

当尝试添加重复项时,JPA 将抛出 PersistenceException 和 ConstraintViolationException。

希望有帮助:)

【讨论】:

  • 我无法在表上创建唯一键,这就是问题所在(由于其他情况,在多租户数据库中)。所以我需要一种高于数据库级别的方法来锁定其他人,直到创建完成。
  • 想到临时表...不要插入“真实”表,而是插入临时表,让进程复制不重复的行。天哪,我不想维护这样的系统。
【解决方案2】:

首先可以在表上创建唯一约束,如果尝试插入重复,则会抛出异常。

另一件事是将您的transaction isolation level 更改为更严格的(可序列化?)。但是有一个权衡,因为它会减慢您访问数据库的速度。

我建议使用第一种方法,尤其是因为这些冲突不会经常发生,除非在您的负载测试中。

【讨论】:

  • Glassfish 服务器中的事务隔离级别已经是可序列化的,但无法更改数据库。请参阅对上述答案的评论:)
  • 您可以使您的检查方法同步,您可以编写自己的插入原生 SQL,您可以允许重复记录并在之后清理,但这些都是变通方法。再次权衡:防止重复更重要还是保持性能更重要?但我现在想不出任何特定于 JPA 的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-13
  • 2016-07-23
  • 2015-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-24
相关资源
最近更新 更多