为何innodb在对主键索引<=的条件下加锁时会锁住下一条记录

发布于 2022-08-31 09:17:33 字数 1509 浏览 20 评论 0

我的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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浅暮の光 2022-09-07 09:17:33

我认为问题出在 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:本人大四学生,无太多实战经验,如果本人回答有误,还请谅解并多多指教。

风吹过旳痕迹 2022-09-07 09:17:33

也许<= 和>= 会导致mysql不会将主键列 next-key lock降级为record lock,而=的时候会降级,只能是这么理解了。

白龙吟 2022-09-07 09:17:33

大概是数据库的设计问题吧!从id=2开始索引,索引到7时,发现条件不匹配,但是程序可能认为对7发生了索引,所以加了锁,我认为不应该加锁。如果不加PRIMARY KEY,会对每个索引的记录加锁。(纯粹猜,没看过源码!!!)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文