我通过以下查询
在一个交易中锁定了一行START TRANSACTION;
SELECT id FROM children WHERE id=100 FOR UPDATE;
在另一个交易中,我有一个查询如下
START TRANSACTION;
SELECT id FROM children WHERE id IN (98,99,100) FOR UPDATE;
它超出错误锁定等待超时。
这里100已被锁定(在第一次交易中)但是ids 98,99没有被锁定。如果在上面的查询中只有100被锁定,那么有任何可能返回98,99的记录。所以结果应如下所示< / p>
编号
===
98
99
===
应忽略Id 100,因为100被事务锁定。
答案 0 :(得分:5)
MySQL没有办法忽略SELECT中的锁定行。你必须找到一种不同的方法来将一行设置为“已经处理过”。
最简单的方法是在第一个查询中短暂锁定行只是为了将其标记为“已处理”,然后将其解锁并再次锁定以进行剩余的处理 - 第二个查询将等待“短”标记“查询完成,您可以添加显式WHERE条件以忽略已标记的行。如果您不想依赖第一个能够成功完成的操作,则可能需要在时间戳上添加更多复杂性,以便在这些操作失败后进行清理。
答案 1 :(得分:3)
在MySQL中,现在可以看到上一个答案中提到的NOWAIT
选项。它不等待获取行锁,并允许您处理当前未锁定的行。
来自MySQL 8.0.0 Release Notes/Changes in MySQL 8.0.1:
InnoDB现在支持
SKIP LOCKED
和SELECT ... FOR SHARE
选项,SELECT ... FOR UPDATE
和NOWAIT
锁定读取语句。如果请求的行被另一个事务锁定,SKIP LOCKED
会导致语句立即返回。START TRANSACTION; SELECT * FROM tableName FOR UPDATE SKIP LOCKED;
从结果集中删除锁定的行。 See Locking Read Concurrency withNOWAIT
andSKIP LOCKED
样本用法(输出的完整示例可以在上面的链接中找到):
SKIP LOCKED
此外,也可以在此处参考手册中包含警告:
跳过锁定行的查询会返回数据的不一致视图。因此,
{ "tokens": { "gift_name": "Cool Gift", "price": "$20" } }
不适合一般的交易工作。但是,当多个会话访问同一个类似队列的表时,它可用于避免锁争用。
答案 2 :(得分:0)
根据http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
解决方案是使用SELECT
:
LOCK IN SHARE MODE
SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;