我在 MySQL 中有一个表,表示要处理的链接队列。链接由外部应用程序一一处理,最后删除。这是一个大容量队列,我有处理应用程序的多个实例,分布在多个服务器上。
如何确保每条记录仅由一个应用程序选取?有没有办法标记/锁定记录?
现在,为了避免两个或多个获取相同的链接,我只允许每个实例获取一组特定的记录(基于其 ID 的 MOD),但这不是增加队列处理的透明方式只需添加新实例即可加快速度。
第一:MySQL 是实现这一点的最糟糕的软件之一,特别是如果它非常动态。原因是像 MEMORY 和 MyISAM 这样的引擎只有全表锁,而像 InnoDB 这样更合适的引擎有更高的写惩罚(提供 ACID 属性),并且针对访问空间和时间上接近的记录(那些设置在内存上)进行了优化)。MySQL 也没有一个好的更改通知系统——它必须作为轮询来实现。有许多针对该任务进行了更优化的软件。
话虽如此,如果性能/效率要求不是很高,我已经看到成功实现这种访问。许多人无法只为一小部分业务逻辑引入和维护一个完整的独立技术。
SELECT FOR UPDATE是您正在寻找的 - 读取序列化。虽然 UPDATE/DELETE 将始终在运行 MYSQL 事务期间锁定该行,但您可能希望在进程进行时避免大型事务,因此:
START TRANSACTION;
SELECT * FROM your_table WHERE state != 'PROCESSING'
ORDER BY date_added ASC LIMIT 1 FOR UPDATE;
if (rows_selected = 0) { //finished processing the queue, abort}
else {
UPDATE your_table WHERE id = $row.id SET state = 'PROCESSING'
COMMIT;
// row is processed here, outside of the transaction, and it can take as much time as we want
// once we finish:
DELETE FROM your_table WHERE id = $row.id and state = 'PROCESSING' LIMIT 1;
}
Run Code Online (Sandbox Code Playgroud)
MySQL 会在选择行时锁定除一个之外的所有并发选择。由于这可能会同时导致大量锁定连接,因此请使初始事务尽可能小,并尝试一次处理多于 1 行。