【问题标题】:using java lock or catch database exception使用 java lock 或 catch 数据库异常
【发布时间】:2019-02-28 04:38:23
【问题描述】:

每次有新数据进来,我都会检查数据库,如果有与新数据相关的记录,我会得到它并根据新数据和旧记录更新记录;如果不存在记录,我将为新数据创建一个新记录;

问题:当有多个线程做同样的事情时,自然会形成read -> check -> update 模式,从而产生race condition


我尝试了以下解决方案,但它们似乎都不太好。

  1. aFieldOrSeveralFields添加唯一约束到db,尝试捕捉SQLIntegrityConstraintViolationException然后重试read -> check -> update进程;

    • 我可以捕捉到Exception,但它在我看来危险
    • 或者我可以通过e instanceof SQLIntegrityConstraintViolationException 进行检查,让其他异常冒出来,但它看起来
  2. 对整个read -> check -> update使用synchronised但似乎相当无效,因为有明显的I/O操作。


2019 年 3 月 11 日更新

最后,为了平衡丑陋的处理效果,我使用synchronised将任务拆分为更小的任务,以确保数据的一致性,直到现在没有明显的性能问题上升。

【问题讨论】:

    标签: java postgresql hibernate spring-boot race-condition


    【解决方案1】:

    我认为你在做正确的事,但我不明白为什么这里会抛出异常? (也许你可以澄清一下)。

    在我看来,正确的流程是这样的:

    record <- readFromDB(uniqueFields)
    if record does not exist:
        record <- createRecord()
    updateFields(record) //here you should update the non-unique fields
    saveToDB(record)     //it shouldn't throw an exception since the unique fields didn't change
    

    另一种可能的解决方案是根据您的用例使用 ON DUPLICATE KEY UPDATE/IGNORE,阅读更多相关信息here

    【讨论】:

    • 抱歉,我认为您误解了我的问题。请您检查问题中的要求吗?谢谢你:)
    • 对不起,不够清楚,能解释一下吗?
    • 很抱歉我的抽象不好,我会更新它并在更新后通知您....对不起,祝您有美好的一天!
    • 抱歉耽搁了,我刚刚更新了我的问题。我希望它现在可以更好地表达我的意图。
    【解决方案2】:

    实际上,这取决于您的服务场景。如果您需要立即回调,有三种方式。

    第一个,悲观锁。这个用在与钱相关的场景中,比如账户余额。

    select xx from xxx.. for update
    //check
    //update 
    

    第二个,乐观锁。如果您对第一个效率不满意。这也许是你的选择。同时,如果出现竞争情况,您必须承担复杂的计划。简单地抛出异常不是企业计划。

    select version, xxx,... from ... //version column is for optimistic lock
    //check
    update .... set ... where version = (the version you get above)
    

    或者,也许您可​​以尝试使用消息队列的事件驱动模型

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-12
      • 2016-10-06
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 2014-01-08
      相关资源
      最近更新 更多