一个需要避免的InnoDB间隙锁

开发 项目管理
在为一个客户排除死锁问题时我遇到了一个有趣的包括InnoDB间隙锁的情形。对于一个WHERE子句不匹配任何行的非插入的写操作中,我预期事务应该不会有锁,但我错了。让我们看一下这张表及示例UPDATE。

在为一个客户排除死锁问题时我遇到了一个有趣的包括InnoDB间隙锁的情形。对于一个WHERE子句不匹配任何行的非插入的写操作中,我预期事务应该不会有锁,但我错了。让我们看一下这张表及示例UPDATE。

  1. mysql> SHOW CREATE TABLE preferences \G 
  2. *************************** 1. row *************************** 
  3.        Table: preferences 
  4. Create TableCREATE TABLE `preferences` ( 
  5.   `numericId` int(10) unsigned NOT NULL
  6.   `receiveNotifications` tinyint(1) DEFAULT NULL
  7.   PRIMARY KEY (`numericId`) 
  8. ) ENGINE=InnoDB DEFAULT CHARSET=latin1 
  9. 1 row in set (0.00 sec) 
  10. mysql> BEGIN
  11. Query OK, 0 rows affected (0.00 sec) 
  12. mysql> SELECT COUNT(*) FROM preferences; 
  13. +----------+ 
  14. COUNT(*) | 
  15. +----------+ 
  16. |        0 | 
  17. +----------+ 
  18. 1 row in set (0.01 sec) 
  19. mysql> UPDATE preferences SET receiveNotifications='1' WHERE numericId = '2'
  20. Query OK, 0 rows affected (0.01 sec) 
  21. Rows matched: 0  Changed: 0  Warnings: 0 

InnoDB状态显示这个UPDATE在主索引记录上持有了一个X锁:

  1. ---TRANSACTION 4A18101, ACTIVE 12 sec 
  2. 2 lock struct(s), heap size 376, 1 row lock(s) 
  3. MySQL thread id 3, OS thread handle 0x7ff2200cd700, query id 35 localhost msandbox 
  4. Trx read view will not see trx with id >= 4A18102, sees < 4A18102 
  5. TABLE LOCK table `test`.`preferences` trx id 4A18101 lock mode IX 
  6. RECORD LOCKS space id 31766 page no 3 n bits 72 index `PRIMARY` of table `test`.`preferences` trx id 4A18101 lock_mode X 

这是为什么呢,Heikki在其bug报告中做了解释,这很有意义,我知道修复起来很困难,但略带厌恶地我又希望它能被差异化处理。为完成这篇文章,让我证明下上面说到的死锁情况,下面中mysql1是第一个会话,mysql2是另一个,查询的顺序如下:

  1. mysql1> BEGIN
  2. Query OK, 0 rows affected (0.00 sec) 
  3. mysql1> UPDATE preferences SET receiveNotifications='1' WHERE numericId = '1'
  4. Query OK, 0 rows affected (0.00 sec) 
  5. Rows matched: 0 Changed: 0 Warnings: 0 
  6. mysql2> BEGIN
  7. Query OK, 0 rows affected (0.00 sec) 
  8. mysql2> UPDATE preferences SET receiveNotifications='1' WHERE numericId = '2'
  9. Query OK, 0 rows affected (0.00 sec) 
  10. Rows matched: 0 Changed: 0 Warnings: 0 
  11. mysql1> INSERT INTO preferences (numericId, receiveNotifications) VALUES ('1''1'); -- This one goes into LOCK WAIT 
  12. mysql2> INSERT INTO preferences (numericId, receiveNotifications) VALUES ('2''1'); 
  13. ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction 

现在你看到导致死锁是多么的容易,因此一定要避免这种情况——如果来自于事务的INSERT部分导致非插入的写操作可能不匹配任何行的话,不要这样做,使用REPLACE INTO或使用READ-COMMITTED事务隔离。

原文链接:http://www.oschina.net/translate/one-more-innodb-gap-lock-to-avoid

责任编辑:陈四芳 来源: 开源中国编译
相关推荐

2016-12-26 18:51:34

AndroidJavascriptJSONObject

2016-11-24 15:54:06

androidJSONObject

2023-12-06 07:33:20

MySQL锁事间隙锁

2024-01-16 12:19:08

MySQL重要机制高并发

2021-12-14 08:10:00

MySQL行锁间隙锁

2020-10-20 13:50:47

MySQL数据库

2023-11-06 08:35:08

表锁行锁间隙锁

2022-04-19 10:29:56

外包误区IT外包IT领导者

2020-02-28 08:29:34

IT网络信息

2022-10-11 07:20:56

YAML字符串语言

2022-04-29 11:39:28

MySQL幻读Gap Lock

2022-01-17 08:56:05

CSS 技巧代码重构

2020-02-18 20:28:23

AI人工智能

2017-08-01 09:35:03

2018-04-25 06:21:57

多云云计算IT

2023-01-31 08:00:00

开源开发软件

2019-08-22 08:53:57

IT现代化数字化转型

2018-11-18 16:31:14

Kubernetes监控容器

2022-10-24 08:02:14

MySQL索引类型

2022-04-27 07:21:06

HTTPAPI系统
点赞
收藏

51CTO技术栈公众号