当前位置: 首页 > 面试题库 >

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

全弘深
2023-03-14
问题内容

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

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

AAAA
BBBB
AACC
BBCC
AADD
BBDD

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

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


问题答案:

第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线程读取操作并将其推送到数据库服务器。

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

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



 类似资料:
  • 问题内容: 我有一个线程需要读取平面文件并进行解析。我需要创建一个新线程来解析该文件的某些部分,稍后该线程将需要更新原始实体的状态,原始实体也将对其进行解析和更新。如何处理这种情况? 我收到的平面文件包含以下示例记录: 首先,该文件以状态保存在数据库中。现在,所有以或开头的记录都需要在单独的线程中进行处理。成功解析后,两个线程都将尝试将数据库中此文件对象的状态更新为。在某些情况下,我得到了。 _编

  • 问题内容: 在我的Java应用程序中,多个线程一次更新同一行如何获得一致性结果? 例如 问题答案: 有两种可能的方法。 您要么选择悲观方法,要么锁定行,表甚至行范围。 或者您使用版本化的实体(乐观锁定)。 也许您可以在这里找到更多信息: https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/transactions.html

  • 我有一个cron作业每30秒运行一次,检查未结束的游戏。我将用于固定线程池。cron作业调用此方法: 其中是。在方法内部,我在循环中调用一个api,直到没有下一个页面。在这个方法中,我想更新数据库,以记住我最后看到的页面。 是否可以在一个线程中更新数据库,然后启动另一个线程,其中数据库再次更新?

  • 在我的REST API中,我有一个过滤器,该过滤器检查每个请求,以查看令牌是否是原样。下面是代码。 当用户登录到应用程序时,将调用上述代码。但是,令牌将在60分钟内过期。我知道,在令牌过期后,要么我必须带用户返回登录屏幕,要么刷新令牌。我把这里和这里的建议都看了一遍 但我不明白以下几点。 如何分配并将此令牌发送回用户?当前,当用户登录时,他将获得令牌并将其保存在一个变量中。为了使刷新的令牌工作,我

  • 问题内容: 我使用的不是可重入的库(用C编写)(即库中没有函数可重入)。假设我已经通过System.load加载了库以获取句柄“ v”。由于重入问题(尝试过但无意义的结果),我无法在两个线程中使用v。我可以使用锁,但这会破坏我本可以获得的任何并行性。 我想做的是启动两个线程,然后在每个线程中加载库以获取两个不同的句柄(因此,加载的库有两个副本)。 这在Java中可行吗?问候Saptarshi 问题

  • 问题内容: 如何只更新数据库上的一条记录? 桌子: 更新查询: 但是我每次只需要更新一行 问题答案: 您可以使用ROWCOUNT 或者您可以使用更新顶部