如何“锁定”正在处理的数据库行

时间:2017-01-17 08:03:48

标签: ruby database multithreading algorithm language-agnostic

我有一个数据库,其中包含正在访问这些行的行和多个线程,在函数中输入一些数据,生成输出,然后用输出填充行的缺失列。

以下是问题:每行都有一个unprocessed标志,默认情况下为true。所以每个线程都在寻找带有这个标志的行。但是每个线程都获得了SAME行,事实证明......因为在线程的工作完成后,该行被标记为已处理,这可能在几秒钟后发生。

我避免这种情况的一种方法是为每一行插入currently_processed标志,将其标记为false,一旦线程访问该行,将其更改为true。然后当线程完成时,只需更改为if。这个问题是我必须使用某种锁定,并且在发生这种情况之前不允许任何其他线程做任何事情。我想知道是否有一种替代方法,我不必进行线程锁定(通过互斥或其他东西),从而减慢整个过程。

如果它有帮助,代码是在Ruby中,但这个问题与语言无关,但这里是用于演示我正在使用的线程类型的代码。所以没什么特别的,像几乎所有语言一样在最低级别进行线程化:

3.times do
  Thread.new do
   row = get_database_row
   result = do_some_processing(row)
   insert_results_into_row(result)
  end
end.each(&:join)

2 个答案:

答案 0 :(得分:2)

这里的“真实”答案是您需要数据库事务。当一个线程获得该行时,数据库需要知道该行当前正在进行处理。

您无法在应用程序中解决此问题!你看,当两个线程同时看同一行时,他们可以两个尝试写那个标志......是的,它肯定会改为“当前处理”;然后两个线程都会更新行数据并将其写回。如果任何处理导致相同最终结果,那么这可能不是问题;但如果没有,则会出现各种数据完整性问题。

所以真正的答案是你退一步看看你的特定数据库是如何设计的,以便处理这些事情。

答案 1 :(得分:0)

  

我想知道是否有一种替代方法,我不必进行线程锁定(通过互斥锁或其他东西),从而减慢整个过程。

有一些方法可以做到这一点:

1)所有线程的一个常见调度程序。它应该读取所​​有行并将它们放入共享队列中,处理theads将获取行。

2)深入研究数据库,找出它是否支持类似oracles的“select for update skip locking”语法并使用它。对于oracle,你需要在游标中使用他的语法并进行一些繁琐的交互,但至少它可以这样工作。

3)分区输入,例如,工作线程的索引。因此,3个中的第一个工人只会处理第1,4,7行等。第二个工人只会处理第2,5,8行等。