【发布时间】:2016-01-29 10:34:30
【问题描述】:
当我们在 MySQL 中使用 InnoDB 表进行“SELECT FOR UPDATE”时,有什么方法可以跳过“锁定的行”?
例如:终端 t1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select id from mytable ORDER BY id ASC limit 5 for update;
+-------+
| id |
+-------+
| 1 |
| 15 |
| 30217 |
| 30218 |
| 30643 |
+-------+
5 rows in set (0.00 sec)
mysql>
同时终端t2:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select id from mytable where id>30643 order by id asc limit 2 for update;
+-------+
| id |
+-------+
| 30939 |
| 31211 |
+-------+
2 rows in set (0.01 sec)
mysql> select id from mytable order by id asc limit 5 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
因此,如果我启动一个查询,强制它选择其他行,那很好。
但是有没有办法跳过锁定的行?
我猜这应该是并发过程中的冗余问题,但是我没有找到任何解决方案。
编辑: 实际上,我的不同并发进程正在做一些显然非常简单的事情:
获取第一行(不包含特定标志 - 例如:“WHERE myflag_inUse!=1”)。
一旦我得到“选择更新”的结果,我就会更新标志并提交行。
所以我只想选择尚未锁定的行以及 myflag_inUse!=1...
以下链接可以帮助我理解为什么会超时,但不能帮助我理解如何避免它:
MySQL 'select for update' behaviour
mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+-------------------------+
| Variable_name | Value |
+-------------------------+-------------------------+
| innodb_version | 5.5.46 |
| protocol_version | 10 |
| slave_type_conversions | |
| version | 5.5.46-0ubuntu0.14.04.2 |
| version_comment | (Ubuntu) |
| version_compile_machine | x86_64 |
| version_compile_os | debian-linux-gnu |
+-------------------------+-------------------------+
7 rows in set (0.00 sec)
【问题讨论】:
-
不要使用
SELECT FOR UPDATE。长时间使用更新锁是一个坏主意,并且仅在使用游标时才真正有用(也不是一个好主意)。您不能使用它来模拟签入/签出机制 -
@PanagiotisKanavos,我不想模仿这种机制。我只想通过跳过锁定的行来选择更新。
-
修复另一笔交易,这样它就不会花这么长时间!
-
@RickJames,修复交易是什么意思?提交/回滚?如果是,实际上我有一个相当复杂的 sql 查询正在运行,这已经花费了一些时间......所以所有并发请求总是在等待另一个选择以进行更新查询......
-
向我们展示另一笔交易;让我们讨论一下可以为此做些什么。也就是说,这个问题是“责备受害者”;让我们去追捕“恶棍”。
标签: mysql sql multithreading concurrency innodb