使用java锁或catch数据库异常

问题描述 投票:0回答:2

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

问题:当有几个线程做同样的事情时,它自然会形成一个read -> check -> update模式,导致race condition


我尝试过以下解决方案,但两者似乎都不太好。

  1. aFieldOrSeveralFields添加db的唯一约束,尝试捕获SQLIntegrityConstraintViolationException,然后重试read -> check -> update进程; 我可以抓住Exception,但它看起来很危险; 或者我可以通过e instanceof SQLIntegrityConstraintViolationException检查它,让其他例外泡沫起来,但它看起来很难看;
  2. 使用synchronised到整个read -> check -> update,但由于有明显的I / O操作,它似乎非常无效。

Updated 2019-03-11

最后,为了平衡丑陋的处理和有效性,我使用synchronised将任务拆分为较小的任务以确保数据一致性,并且到目前为止没有明显的性能问题上升。

java postgresql hibernate spring-boot race-condition
2个回答
0
投票

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

正如我所看到的,正确的流程如下:

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


0
投票

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

第一个,悲观锁定。这个用于与资金相关的场景,如账户余额。

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)

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

© www.soinside.com 2019 - 2024. All rights reserved.