Mysql SELECT FOR UPDATE - 奇怪的问题

时间:2010-03-29 19:28:21

标签: mysql locking blocking

我有一个奇怪的问题(至少对我来说:))与MySQL的锁定工具。

我有一张桌子:

create table `test` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,  
  PRIMARY KEY (`id`)  
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1

有了这些数据:

  

+ ---- +
  | id |
  + ---- +
  | 3 |
  | 4 |
  | 5 |
  | 6 |
  | 7 |
  | 8 |
  | 10 |
  | 11 |
  | 12 |
  + ---- +

现在我有2个客户端在开头执行这些命令:

  

设置autocommit = 0;
  设置会话事务隔离级别可序列化;
  开始;

现在最有趣的部分。第一个客户端执行此查询:(意图插入id等于9的行)

  

SELECT * from test where id = 9 FOR UPDATE;
  空集(0.00秒)

然后第二个客户端也这样做:

  

SELECT * from test where id = 9 FOR UPDATE;
  空集(0.00秒)

我的问题是:为什么第二个客户端没有阻止?应该由第一个查询设置独占间隙锁,因为已使用FOR UPDATE而第二个客户端应该阻止。

如果我错了,有人可以告诉我如何正确地做到这一点吗?

我使用的MySql版本是:5.1.37-1ubuntu5.1

2 个答案:

答案 0 :(得分:3)

因为在那个时候,返回(空)结果是安全的 - 没有锁定为id = 9的记录设置,因为它不存在因此无法更新 - 我认为你不能在这种情况下依靠innodb设置读锁。它应该在id = 9上设置写锁定。

如果稍后,其中一个事务确实更新了表,并触摸与另一个事务相同的数据 - 更新可能会在其中一个事务中阻塞,如果另一个事务提交该数据,则稍后会失败。在这样的情况下交易失败是完全正常的 - 让你去处理它 - 这通常是重试交易的问题。

如果有一个id = 9的记录,你可能会看到2. select块,直到第一个事务完成,因为现在有一个记录必须被锁定以防第一个事务决定更新该行。

答案 1 :(得分:-1)