一尘不染

如何正确处理两个线程更新数据库中的同一行

hibernate

我有一个线程T1需要读取平面文件并进行解析。我需要创建一个新线程T2来解析该文件的某些部分,然后此T2线程将需要更新原始实体的状态,原始实体也将通过原始线程对其进行解析和更新。T1如何处理这种情况?

我收到的平面文件包含以下示例记录:

AAAA
BBBB
AACC
BBCC
AADD
BBDD

首先,该文件以Received状态保存在数据库中。现在,所有以BB或开头的记录都AA需要在单独的线程中进行处理。成功解析后,两个线程都将尝试将数据库中此文件对象的状态更新为Parsed。在某些情况下,我得到了staleObjectException
_编辑:丢失异常之前,任何线程完成的工作。 我们正在使用乐观锁定。_避免此问题的最佳方法是什么?

上面的帖子有助于理解其中的某些部分,但无助于解决我的问题。


阅读 1268

收藏
2020-06-20

共1个答案

一尘不染

第1部分-您的问题

收到此异常的主要原因是您正在使用带有 乐观锁定的 Hibernate 。这主要是告诉你,要么线程T1或线程T2已经更新了状态 PARSED
现在其他线程持有旧版本的数据行比保存在数据库中的一个较小的版本,并试图状态更新到 PARSED 以及。

这里的问题是“ 两个线程是否试图保留相同的数据
?”。如果答案是肯定的,那么即使最后一次更新成功,也不会有任何问题,因为最终他们会将行更新为相同状态。在这种情况下,您不需要乐观锁定,因为无论如何您的数据都是同步的。

如果状态设置为之后的主要问题来自 收到
如果两个线程T1和T2实际上取决于彼此正在重置到下一个状态的时候。在这种情况下,您需要确保如果T1首先执行(反之亦然),则T2需要刷新已更新行的数据,并根据T1已推送的更改重新应用其更改。在这种情况下,解决方法如下。如果遇到staleObjectException,则基本上需要从数据库刷新数据并重新启动操作。

在发布的链接上的第2部分分析
两个线程更新同一Object时可能出现的hibernate异常? 方法1 ,这或多或少是
最后更新Wins的 情况。它或多或少避免了乐观锁定(版本计数)。如果您没有从T1到T2的依赖关系,或者没有反向关系来设置状态 PARSED
。这应该很好。

方法2乐观锁定 这就是您现在拥有的。解决方案是刷新数据并重新开始操作。

方法3行级DB锁
这里的解决方案与方法2大致相同,只是对悲观锁的要求稍加修正。主要区别在于,在这种情况下,它可能是READ锁,并且如果是PESSIMISTICREAD,则可能甚至无法从数据库读取数据来刷新它。

Aproach 4应用程序级同步
有许多不同的同步方法。一个示例是将所有更新实际安排在BlockingQueue或JMS队列中(如果您希望它是持久的),然后从单个线程推送所有更新。为了使它形象化,T1和T2会将元素放入队列,并且只有一个T3线程读取操作并将其推送到数据库服务器。

如果使用应用程序级同步,则应注意,在多服务器部署中不能分发所有结构。

好吧,我暂时别无其他:)

2020-06-20