iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >MySQL的InnoDB锁机制介绍
  • 481
分享到

MySQL的InnoDB锁机制介绍

2024-04-02 19:04:59 481人浏览 八月长安
摘要

这篇文章主要介绍“Mysql的InnoDB锁机制介绍”,在日常操作中,相信很多人在mysql的InnoDB锁机制介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Mysql的

这篇文章主要介绍“Mysql的InnoDB机制介绍”,在日常操作中,相信很多人在mysql的InnoDB锁机制介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Mysql的InnoDB锁机制介绍”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一  背景
    MySQL锁机制是一个极其复杂的实现,为数据库并发访问和数据一致提供保障。这里仅仅针对MySQL访问数据的三种锁做介绍,加深自己对锁方面的掌握。
二 常见的锁机制
我们知道对于InnoDB存储引擎而言,MySQL 的行锁机制是通过在索引上加锁来锁定要目标数据行的。常见的有如下三种锁类型,本文未声明情况下都是在RR 事务隔离级别下的描述。
2.1 Record Locks 
  记录锁实际上是索引上的锁,锁定具体的一行或者多行记录。当表上没有创建索引时,InnoDB会创建一个隐含的聚族索引,并且使用该索引锁定数据。通常我们可以使用 show innodb status 看到行锁相关的信息。
2.2 Gap Locks
 间隙锁是锁定具体的范围,但是不包含行锁本身。比如

  1. select * from  tab where id>10 and id<20;

RR事务隔离级别下会锁定10-20之间的记录,不允许类似15这样的值插入到表里,以便消除“幻读”带来的影响。间隙锁的跨度可以是1条记录(Record low就可以认为是一个特殊的间隙锁 ,多行,或者为空。当访问的字段是唯一键/主键时,间隙锁会降级为Record lock。RR事务隔离级别下访问一个空行 ,也会有间隙锁,后续会举例子说明。
我们可以通过将事务隔离级别调整为RC 模式或者设置innodb_locks_unsafe_for_binlog=1 (该参数已经废弃)来禁用Gap锁。

2.3 Next-Key Locks
  是Record Lock+Gap Locks,锁定一个范围并且包含索引本身。例如索引值包含 2,4,9,14 四个值,其gap锁的区间如下:
  (-∞,2],(2,4],(4,9],(9,14],(14,+∞)
本文着重从主键,唯一键、非唯一索引,不存在值访问四个方面来阐述RR模式下锁的表现。
三 测试案例
3.1 主键/唯一键 

  1. CREATE TABLE `lck_primarkey` (

  2.   `id` int(11) NOT NULL,

  3.    val int(11) not null default 0,

  4.   primary key (`id`),

  5.   key  idx_val(val)

  6. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  7. insert into lck_primarkey values(2,3),(4,5),(9,8),(14,13)

会话1 

  1. [session1] >select * from   lck_primarkey;

  2. +----+-----+

  3. | id | val |

  4. +----+-----+

  5. | 2 | 3 |

  6. | 4 | 5 |

  7. | 9 | 8 |

  8. | 14 | 13 |

  9. +----+-----+

  10. 4 rows in set (0.00 sec)

  11. [session1] >begin;

  12. Query OK, 0 rows affected (0.00 sec)

  13. [session1] >select * from lck_primarkey  where id=9 for update;

  14. +----+-----+

  15. | id | val |

  16. +----+-----+

  17. | 9 | 8 |

  18. +----+-----+

  19. 1 row in set (0.00 sec)

会话2 

  1. [session2] >begin;

  2. Query OK, 0 rows affected (0.00 sec)

  3. [session2] >insert into lck_primarkey values(7,6);

  4. Query OK, 1 row affected (0.00 sec)

  5. [session2] >insert into lck_primarkey values(5,5);

  6. Query OK, 1 row affected (0.00 sec)

  7. [session2] >insert into lck_primarkey values(13,13);

  8. Query OK, 1 row affected (0.00 sec)

  9. [session2] >insert into lck_primarkey values(10,9);

  10. Query OK, 1 row affected (0.00 sec)

分析
   从例子看,当访问表的where字段是主键或者唯一键的时候,session2中的插入操作并未被 session1 中的id=8 影响。官方表述

  1. “Gap locking is not needed for statements that lock rows using a unique index to search for a unique row. (This does not include the case that the search condition includes only some columns of a multiple-column unique index; in that case, gap locking does occur.) For example, if the id column has a unique index, the following statement uses only an index-record lock for the row having id value 100 and it does not matter whether other sessions insert rows in the preceding gap:

  2.    select * from tab where id=100 for update”

  3. 就是说当语句通过主键或者唯一键访问数据的时候,Innodb会使用Record lock锁住记录本身,而不是使用间隙锁锁定范围。

需要注意以下两种情况:
1 通过主键或则唯一索引访问不存在的值,也会产生GAP锁。

  1. [session1] >begin;

  2. Query OK, 0 rows affected (0.00 sec)

  3. [session1] >select * from lck_primarkey  where id=7 for update;

  4. Empty set (0.00 sec)

  5. [session2] >insert into lck_primarkey values(8,13);

  6. ^CCtrl-C -- sending "KILL QUERY 303042481" to server ...

  7. Ctrl-C -- query aborted.

  8. ERROR 1317 (70100): Query execution was interrupted

  9. [session2] >insert into lck_primarkey values(5,13);

  10. ^CCtrl-C -- sending "KILL QUERY 303042481" to server ...

  11. Ctrl-C -- query aborted.

  12. ERROR 1317 (70100): Query execution was interrupted

  13. [session2] >insert into lck_primarkey values(3,13);

  14. Query OK, 1 row affected (0.00 sec)

  15. [session2] >insert into lck_primarkey values(10,13);

  16. Query OK, 1 row affected (0.00 sec)

2 通过唯一索引中的一部分字段来访问数据,比如unique key(a,b,c) ,select * from tab where a=x and b=y; 读者朋友可以自己做这个例子。

3.2 非唯一键

  1. CREATE TABLE `lck_secondkey` (

  2.   `id` int(11) NOT NULL,

  3.    KEY `idx_id` (`id`)

  4. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  5. insert into lck_secondkey values(2),(4),(9),(14)

会话1

  1. [session1] >begin ;

  2. Query OK, 0 rows affected (0.00 sec)

  3. [session1] >select * from lck_secondkey;

  4. +----+

  5. | id |

  6. +----+

  7. | 2 |

  8. | 3 |

  9. | 4 |

  10. | 9 |

  11. | 14 |

  12. +----+

  13. 5 rows in set (0.00 sec)

  14. [session1] >select * from lck_secondkey where id=9 for update;

  15. +----+

  16. | id |

  17. +----+

  18. | 9 |

  19. +----+

  20. 1 row in set (0.00 sec)

会话2

  1. [session2] >begin;

  2. Query OK, 0 rows affected (0.00 sec)

  3. [session2] >insert into lck_secondkey values(3);

  4. Query OK, 1 row affected (0.00 sec)

  5. [session2] >insert into lck_secondkey values(4);

  6. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  7. Ctrl-C -- query aborted.

  8. ERROR 1317 (70100): Query execution was interrupted

  9. [session2] >insert into lck_secondkey values(5);

  10. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  11. Ctrl-C -- query aborted.

  12. ERROR 1317 (70100): Query execution was interrupted

  13. [session2] >insert into lck_secondkey values(6);

  14. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  15. Ctrl-C -- query aborted.

  16. ERROR 1317 (70100): Query execution was interrupted

  17. [session2] >insert into lck_secondkey values(7);

  18. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  19. Ctrl-C -- query aborted.

  20. ERROR 1317 (70100): Query execution was interrupted

  21. [session2] >insert into lck_secondkey values(8);

  22. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  23. Ctrl-C -- query aborted.

  24. ERROR 1317 (70100): Query execution was interrupted

  25. [session2] >insert into lck_secondkey values(9);

  26. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  27. Ctrl-C -- query aborted.

  28. ERROR 1317 (70100): Query execution was interrupted

  29. [session2] >insert into lck_secondkey values(10);

  30. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  31. Ctrl-C -- query aborted.

  32. ERROR 1317 (70100): Query execution was interrupted

  33. [session2] >insert into lck_secondkey values(11);

  34. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  35. Ctrl-C -- query aborted.

  36. ERROR 1317 (70100): Query execution was interrupted

  37. [session2] >insert into lck_secondkey values(12);

  38. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  39. Ctrl-C -- query aborted.

  40. ERROR 1317 (70100): Query execution was interrupted

  41. [session2] >insert into lck_secondkey values(13);

  42. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  43. Ctrl-C -- query aborted.

  44. ERROR 1317 (70100): Query execution was interrupted

  45. [session2] >insert into lck_secondkey values(14);

  46. Query OK, 1 row affected (0.00 sec)

分析
  事务1 对id=9进行for update 访问,session2 插入[4,13]的值都是失败的。根据MySQL的锁原理,Innodb 范围索引或者表是通过Next-key locks 算法,RR事务隔离级别下,通过非唯一索引访问数据行并不是锁定唯一的行,而是一个范围。从例子上可以看出来MySQL对 [4,9] 和(9,14]之间的记录加上了锁,防止其他事务对4-14范围中的值进行修改。可能有读者对其中 id=4 不能修改,但是id=14的值去可以插入有疑问?可以看接下来的例子

  1. [session1] >select * from  lck_primarkey;

  2. +----+-----+

  3. | id | val |

  4. +----+-----+

  5. | 2 | 3 |

  6. | 4 | 5 |

  7. | 9 | 8 |

  8. | 14 | 13 |

  9. +----+-----+

  10. 4 rows in set (0.00 sec)

  11. [session1] >begin;

  12. Query OK, 0 rows affected (0.00 sec)

  13. [session1] >select * from  lck_primarkey  where  val=8 for update;

  14. +----+-----+

  15. | id | val |

  16. +----+-----+

  17. | 9 | 8 |

  18. +----+-----+

  19. 1 row in set (0.00 sec)

会话2

  1. [session2] >begin;

  2. Query OK, 0 rows affected (0.00 sec)

  3. [session2] >insert into lck_primarkey values(3,5);

  4. Query OK, 1 row affected (0.00 sec)

  5. [session2] >insert into lck_primarkey values(15,13);

  6. Query OK, 1 row affected (0.00 sec)

  7. [session2] >select * from lck_primarkey;

  8. +----+-----+

  9. | id | val |

  10. +----+-----+

  11. | 2 | 3 |

  12. | 3 | 5 |

  13. | 4 | 5 |

  14. | 9 | 8 |

  15. | 14 | 13 |

  16. | 15 | 13 |

  17. +----+-----+

  18. 6 rows in set (0.00 sec)

  19. [session2] >insert into lck_primarkey values(16,12);

  20. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  21. Ctrl-C -- query aborted.

  22. ERROR 1317 (70100): Query execution was interrupted

  23. [session2] >insert into lck_primarkey values(16,6);

  24. ^CCtrl-C -- sending "KILL QUERY 303040567" to server ...

  25. Ctrl-C -- query aborted.

  26. ERROR 1317 (70100): Query execution was interrupted

  27. [session2] >insert into lck_primarkey values(16,5);

  28. ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

  29. [session2] >

  30. [session2] >insert into lck_primarkey values(1,5);

  31. Query OK, 1 row affected (0.00 sec)

分析
   因为session1 对非唯一键val=8 加上了gap锁 [4,5] -[14,13],非此区间的记录都可以插入表中。记录(1,5),(15,13)不在此gap锁区间,记录(16,12),(16,6),(16,5)中的val值在被锁的范围内,故不能插入。

到此,关于“MySQL的InnoDB锁机制介绍”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

您可能感兴趣的文档:

--结束END--

本文标题: MySQL的InnoDB锁机制介绍

本文链接: https://www.lsjlt.com/news/60917.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • oracle怎么查询当前用户所有的表
    要查询当前用户拥有的所有表,可以使用以下 sql 命令:select * from user_tables; 如何查询当前用户拥有的所有表 要查询当前用户拥有的所有表,可以使...
    99+
    2024-05-14
    oracle
  • oracle怎么备份表中数据
    oracle 表数据备份的方法包括:导出数据 (exp):将表数据导出到外部文件。导入数据 (imp):将导出文件中的数据导入表中。用户管理的备份 (umr):允许用户控制备份和恢复过程...
    99+
    2024-05-14
    oracle
  • oracle怎么做到数据实时备份
    oracle 实时备份通过持续保持数据库和事务日志的副本来实现数据保护,提供快速恢复。实现机制主要包括归档重做日志和 asm 卷管理系统。它最小化数据丢失、加快恢复时间、消除手动备份任务...
    99+
    2024-05-14
    oracle 数据丢失
  • oracle怎么查询所有的表空间
    要查询 oracle 中的所有表空间,可以使用 sql 语句 "select tablespace_name from dba_tablespaces",其中 dba_tabl...
    99+
    2024-05-14
    oracle
  • oracle怎么创建新用户并赋予权限设置
    答案:要创建 oracle 新用户,请执行以下步骤:以具有 create user 权限的用户身份登录;在 sql*plus 窗口中输入 create user identified ...
    99+
    2024-05-14
    oracle
  • oracle怎么建立新用户
    在 oracle 数据库中创建用户的方法:使用 sql*plus 连接数据库;使用 create user 语法创建新用户;根据用户需要授予权限;注销并重新登录以使更改生效。 如何在 ...
    99+
    2024-05-14
    oracle
  • oracle怎么创建新用户并赋予权限密码
    本教程详细介绍了如何使用 oracle 创建一个新用户并授予其权限:创建新用户并设置密码。授予对特定表的读写权限。授予创建序列的权限。根据需要授予其他权限。 如何使用 Oracle 创...
    99+
    2024-05-14
    oracle
  • oracle怎么查询时间段内的数据记录表
    在 oracle 数据库中查询指定时间段内的数据记录表,可以使用 between 操作符,用于比较日期或时间的范围。语法:select * from table_name wh...
    99+
    2024-05-14
    oracle
  • oracle怎么查看表的分区
    问题:如何查看 oracle 表的分区?步骤:查询数据字典视图 all_tab_partitions,指定表名。结果显示分区名称、上边界值和下边界值。 如何查看 Oracle 表的分区...
    99+
    2024-05-14
    oracle
  • oracle怎么导入dump文件
    要导入 dump 文件,请先停止 oracle 服务,然后使用 impdp 命令。步骤包括:停止 oracle 数据库服务。导航到 oracle 数据泵工具目录。使用 impdp 命令导...
    99+
    2024-05-14
    oracle
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作