我的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?
也许<= 和>= 会导致mysql不会将主键列 next-key lock降级为record lock,而=的时候会降级,只能是这么理解了。
我认为问题出在 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:本人大四学生,无太多实战经验,如果本人回答有误,还请谅解并多多指教。