这是用例:
我有一张桌子,上面有一堆可用或不可用的唯一代码。作为事务的一部分,我想选择表中可用的代码,然后在事务中更新该行。由于这种情况可能会同时在许多会话中同时发生,因此我希望理想地选择一个随机记录并在表上使用行级锁定,以便其他事务不会被从其中选择行的查询阻塞桌子。
我使用 InnoDB 作为存储引擎,我的查询如下所示:
select * from tbl_codes where available = 1 order by rand() limit 1 for update
然而,它最终不是锁定表中的一行,而是锁定整个表。谁能给我一些关于如何做到这一点的指示,以便此查询不会锁定整个表而只锁定行?
Update
附录:我能够通过在 select 中指定显式键而不是执行 rand() 来实现行级锁定。当我的查询如下所示:
Query 1:
select * from tbl_codes where available = 1 and id=5 limit 1 for update
Query 2:
select * from tbl_codes where available = 1 and id=10 limit 1 for update
然而,这并不能真正帮助解决问题。
附录 2:我采用的最终解决方案
鉴于rand()在MySQL中存在一些问题,我选择的策略是:
-
我选择 50 个代码 ID(其中可用 = 1),然后对应用程序层中的数组进行洗牌,以向顺序添加一定程度的随机性。
从 tbl_codes 中选择 id,可用 = 1 限制 50
-
我开始循环地从打乱的数组中弹出代码,直到能够选择带有锁的代码
从 tbl_codes 中选择 *,其中 available = 1 且 id = :id
查看 MySQL 实际执行此查询的方式可能会很有用:
select * from tbl_codes where available = 1 order by rand() limit 1 for update
这将读取并排序所有匹配的行WHERE
条件下,使用生成随机数rand()
将每一行放入一个虚拟列中,根据该虚拟列对所有行(在临时表中)进行排序,然后从排序集中将行返回给客户端,直到LIMIT
已达到(在本例中只有一个)。这FOR UPDATE
影响整个语句在执行时完成的锁定,因此在读取行时应用该子句在 InnoDB 中, not当它们返回给客户时。
抛开上述明显的性能影响(这很糟糕),您永远不会从中获得合理的锁定行为。
简短回答:
- 选择您想要的行,使用
RAND()
或您喜欢的任何其他策略,以便找到PRIMARY KEY
该行的值。例如。:SELECT id FROM tbl_codes WHERE available = 1 ORDER BY rand() LIMIT 1
- 使用其锁定您想要的行
PRIMARY KEY
仅有的。例如。:SELECT * FROM tbl_codes WHERE id = N
希望这有帮助。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)