提问人:anemaria20 提问时间:1/17/2017 更新时间:1/17/2017 访问量:164
如何“锁定”正在处理的数据库行
How to 'lock' database rows being processed
问:
我有一个数据库,里面装满了行和多个线程,这些线程正在访问这些行,在函数中输入其中的一些数据,生成输出,然后用输出填充行中缺失的列。
问题来了:每行都有一个标志,默认情况下,该标志为 true。因此,每个线程都在寻找带有此标志的行。但是每个线程都得到相同的行,事实证明......因为在线程的作业完成后,该行被标记为已处理,这可能会在几秒钟后发生。unprocessed
我避免这种情况的一种方法是为每一行插入一个标志,将其标记为 false,一旦线程访问该行,将其更改为 true。然后,当线程完成时,只需将 if 改回 false。这样做的问题是我必须使用某种锁定,并且在发生这种情况之前不允许任何其他线程执行任何操作。我想知道是否有另一种方法,我不必进行线程锁定(通过互斥锁或其他东西),从而减慢整个过程。currently_processed
如果有帮助,代码是用 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)
答:
这里的“真正”答案是您需要一个数据库事务。当一个线程获取该行时,数据库需要知道该行当前正在处理。
您无法在应用程序中解决此问题!你看,当两个线程同时查看同一行时,它们都可以尝试编写该标志......是的,它肯定会更改为“当前正在处理”;然后两个线程都将更新行数据并将其写回。如果任何处理导致相同的最终结果,也许这不是问题;但如果没有,那么就会出现各种数据完整性问题。
因此,真正的答案是,你退后一步,看看你的特定数据库是如何设计的,以处理这些事情。
评论
currently_processed
currently_processed
我想知道是否有另一种方法,我不必进行线程锁定(通过互斥锁或其他东西),从而减慢整个过程。
有一些方法可以做到这一点:
1) 所有线程使用一个通用调度程序。它应该读取所有行并将它们放入共享队列中,处理 thead 将从中获取行。
2)更深入地研究数据库,找出它是否支持类似预言机的“select for update skip locking”语法并利用它。对于预言机,你需要在游标中使用他的语法,并进行一些繁琐的交互,但至少它可以以这种方式工作。
3)通过工作线程的索引对输入进行分区。因此,3 个工作线程中的第 1 个工作线程将只处理第 1、4、7 行等,第二个工作线程将仅处理第 2、5、8 行等。
评论