假设您有一个由100k个作业组成的表,每个作业都需要处理。
job_id (int)
job_details (whatever)
job_status (Enum: Not processed, Processing, Processed)
我的核心软件,例如有100个线程处理这些作业,所以每个线程都需要一个工作来处理,它获得一个免费的工作,因此它查询未处理工作,将其标记为处理,完成后将其标记为已处理
问题是当100个线程开始工作时,因为许多线程在查询Select * from jobs where job_status='Not processed' limit 1
update jobs set job_status='processing' where job_id=%JOB_ID%
时会一起开始,因为很多线程都要处理相同的工作!这是非常错误的。
我该如何正确地做到这一点?
答案 0 :(得分:1)
如果jobs
是InnoDB表,那么您可以在事务中使用SELECT ... FOR UPDATE
来分配单个作业:
BEGIN
SELECT * FROM jobs WHERE job_status = 'Not processed' LIMIT 1 FOR UPDATE
UPDATE jobs SET job_status = 'Processing' WHERE job_id = ?
COMMIT
指定FOR UPDATE
锁定所选行。同时执行SELECT
查询的单独事务(线程)将等待第一个事务完成。
或者,如果您修改jobs
表以记录已为该任务分配的线程,则可以在没有事务的情况下执行分配。首先,分配一个作业,将作业的owner_thread
属性设置为某个对执行线程唯一的标识符:
UPDATE jobs
SET job_status = 'Processing', owner_thread = ?
WHERE job_status = 'Not processed'
LIMIT 1
然后使用执行线程的唯一标识符检索已分配的作业的详细信息:
SELECT job_id, job_details FROM jobs WHERE owner_thread = ?