为何innodb在对主键索引<=的条件下加锁时会锁住下一条记录
我的mysql环境:
innodb_version | 5.5.30
version | 5.5.30-log
version_compile_machine | x86_64
version_compile_os | Linux
tx_isolation = REPEATABLE-READ
innodb_locks_unsafe_for_binlog = OFF
我建了一张表:
| A | CREATE TABLE `A` (
`id` int(11) NOT NULL,
`name` varchar(1024) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `i_name` (`name`(255))
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
mysql> select * from A;
+----+------+
| id | name |
+----+------+
| 2 | new |
| 7 | aa |
| 8 | adf |
| 9 | aa |
| 11 | a |
| 12 | bbb |
+----+------+
6 rows in set (0.00 sec)
当我在一个事务里执行下面的sql时
begin;
select * from A where id<=2 for update;
原本认为只会对2记录加锁,但是实际上会锁住2的下一条记录:
TABLE LOCK table `test`.`A` trx id 2F06 lock mode IX
RECORD LOCKS space id 0 page no 420 n bits 80 index `PRIMARY` of table `test`.`A` trx id 2F06 lock_mode X
Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
**0: len 4; hex 80000007; asc ;;**
1: len 6; hex 00000000077f; asc ;;
2: len 7; hex ef000001750128; asc u (;;
3: len 2; hex 6161; asc aa;;
Record lock, heap no 12 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000000002ef1; asc . ;;
2: len 7; hex 1f0000020e0110; asc ;;
3: len 3; hex 6e6577; asc new;;
i don't know why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为问题出在
innodb_locks_unsafe_for_binlog = OFF
,建议您改为 ON 试试。MySQL 锁分为记录锁、间隙锁等。
在您当前场景下 UPDATE 时,InnoDB 首先对所求 id 范围的 where 条件根据 B+ 树索引进行扫描,扫描到的行加行锁。如果
innodb_locks_unsafe_for_binlog
未开启,不匹配的行上的锁也不释放,直到事务结束;如果开启,那么不匹配的行上的锁将被释放。您所遇到的问题可能是由于
innodb_locks_unsafe_for_binlog
配置为 OFF 造成事务结束前间隙锁锁掉了 id 比 2 大的一条记录未释放造成的。PS:本人大四学生,无太多实战经验,如果本人回答有误,还请谅解并多多指教。
也许<= 和>= 会导致mysql不会将主键列 next-key lock降级为record lock,而=的时候会降级,只能是这么理解了。
大概是数据库的设计问题吧!从id=2开始索引,索引到7时,发现条件不匹配,但是程序可能认为对7发生了索引,所以加了锁,我认为不应该加锁。如果不加PRIMARY KEY,会对每个索引的记录加锁。(纯粹猜,没看过源码!!!)