use*_*227 5 mysql select transactions sql-update
我将有多个客户端将数据输入到数据库中,我必须确保事务不会混合在一起。
我在文档中阅读START TRANSACTION
并SELECT ... FOR UPDATE
锁定它读取的每一行:
SELECT ... FOR UPDATE 读取最新的可用数据,在它读取的每一行上设置排他锁。因此,它设置的锁定与搜索的 SQL UPDATE 将在行上设置的锁定相同。
见https://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
所以我登录了一个客户端并输入了这些语句:
START TRANSACTION;
SELECT * FROM productMacAddress WHERE status='free' limit 8 FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)
在此处暂停第二个客户端条目....
UPDATE productMacAddress SET status='testing1' WHERE status='free' LIMIT 8;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
在另一个客户端,我输入:
START TRANSACTION;
SELECT * FROM productMacAddress WHERE status='free' limit 4 FOR UPDATE;
UPDATE productMacAddress SET status='testing2' WHERE status='free' LIMIT 4;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
但是SELECT
在第一个客户完全完成之前,我无法从桌子上做任何事情。为什么会这样?文档指出它应该逐行锁定,特别是因为 I LIMIT 8
.
先感谢您。
Rub*_*ben 10
InnoDB 表的默认隔离级别是可重复读取。当此隔离级别处于活动状态时,我们会得到以下行为(引自:https : //dev.mysql.com/doc/refman/5.5/en/set-transaction.html):
对于锁定读取(SELECT with FOR UPDATE 或 LOCK IN SHARE MODE)、UPDATE 和 DELETE 语句,锁定取决于语句是使用具有唯一搜索条件的唯一索引还是范围类型搜索条件。对于具有唯一搜索条件的唯一索引,InnoDB 只锁定找到的索引记录,而不锁定它之前的间隙。对于其他搜索条件,InnoDB 锁定扫描的索引范围,使用间隙锁或 next-key(间隙加索引记录)锁来阻止其他会话插入范围所覆盖的间隙。
换句话说:您可以尝试在 SELECT 的 WHERE 条件中使用主键吗?因此,例如而不是:
START TRANSACTION;
SELECT * FROM productMacAddress WHERE status='free' limit 8 FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)
尝试:
START TRANSACTION;
SELECT * FROM productMacAddress WHERE id=10 FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)
如果 id 是主键。任何其他带有唯一索引的列也可以使用。在 WHERE 子句中使用非唯一列时,InnoDB 将锁定一系列行。