现在有这样一个函数 processBatch ,负责读取数据,执行一些操作后再更新它们,相关的数据库操作都在事务内执行。伪代码如下:
function processBatch():
tx = db.beginTransaction()
// 1. 批量读取:取出最多 N 条“待处理”数据
items = tx.query("SELECT * FROM tasks WHERE status = 'PENDING' LIMIT N")
for item in items:
// 2. 业务处理
doBusinessLogic(item)
// 3. 更新状态
tx.execute("UPDATE tasks SET status = 'DONE' WHERE id = ?", item.id)
tx.commit()
// 线程 A
spawn threadA:
processBatch()
// 线程 B (几乎同时执行)
spawn threadB:
processBatch()
但由于 processBatch 在多个地方都会被调用,因此存在并发问题。线程 A 和线程 B 执行时可能查询到同一批数据,导致这批数据被处理两次。解决这个问题有两个方案:
- 方案 A:在 processBatch 的逻辑中增加锁,这样在任意时刻,该函数都不会并发执行
- 方案 B:调整数据库事务的隔离级别或锁表,即使 processBatch 并发执行了,底层的数据操作不会出现并发的情况
我的问题是:
- 哪个方案更符合最佳实践?原因是什么
- 在保持 processBatch 会被多个地方调用不变的前提下,有没有更好的方案?
- 如果想学习这类并发相关的问题和解决方案,应该搜索什么关键词
感谢各位赐教