【问题标题】:Hibernate concurrency creating a duplicate record on saveOrUpdateHibernate 并发在 saveOrUpdate 上创建重复记录
【发布时间】:2017-08-14 05:56:04
【问题描述】:

我正在尝试使用 Java、Spring、Hibernate 和 Oracle SQL 实现计数器。每条记录代表一个计数,由给定的时间戳记。假设每条记录由分钟唯一标识,并且每条记录都包含一个计数列。该服务应该会收到大量并发请求,并且我会为可能的相同记录更新一个计数器列。

在我的表中,如果记录不存在,只需将记录插入并将其计数设置为1。否则,通过时间戳找到记录并将其现有计数器列增加1。

为了确保我们保持数据的一致性和完整性,我使用了悲观锁定。例如,如果 20 个计数同时进入,并且不一定来自同一用户,则我们可能会在更新之前从该记录的过时读取中覆盖该记录。通过锁定,我确保如果有 20 个计数,对数据库的净影响应该代表 20 个计数。

所以锁定很好,但问题是,如果记录从一开始就不存在,并且我们有两个或多个并发请求试图更新尚不存在的记录,我观察到插入重复记录是因为我们无法锁定尚不存在的记录。我们如何确保不会在表中创建重复项?是否应该通过 Oracle 控制?或者我可以通过我的应用和 Hibernate 进行管理吗?

谢谢。

【问题讨论】:

    标签: java multithreading oracle hibernate concurrency


    【解决方案1】:

    一个是完全避免此类问题的方法是在您实际查询数据时生成计数。 Oracle 有一个解析函数ROW_NUMBER(),它可以为查询结果集中的每条记录分配一个行号。作为一个粗略的示例,请考虑以下查询:

    SELECT
        ts,
        ROW_NUMBER() OVER (ORDER BY ts) rn
    FROM yourTable
    

    您想要的计数将在rn 列中,表示自表中的第一个条目以来出现的记录数。当然,您可以进一步限制查询。

    这种方法对于删除记录很有效,因为计数总是从 1 开始。一个缺点是 Hibernate 不支持行号功能。您必须将其作为本机查询或存储过程运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-03
      • 2023-03-05
      • 2015-04-01
      • 2013-04-26
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      相关资源
      最近更新 更多