前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL锁相关总结|悲观锁、乐观锁、读锁、写锁、表锁、行锁、页面锁、间隙锁、临键锁

MySQL锁相关总结|悲观锁、乐观锁、读锁、写锁、表锁、行锁、页面锁、间隙锁、临键锁

原创
作者头像
程序员皮皮林
发布2024-09-07 20:55:13
1360
发布2024-09-07 20:55:13
举报
文章被收录于专栏:mysql

MySQL锁总体结构

MySQL 的锁可以分成三类:总体、类型、粒度。

  • 总体上分成两种:乐观锁和悲观锁
  • 类型上也是两种:读锁和写锁
  • 锁的粒度上可以分成五种:表锁,行锁,页面锁,间隙锁,临键锁

下面我们就来详细讲一下这些锁

1. 悲观锁

悲观锁对于数据库中数据的读写持悲观态度,即在整个数据处理的过程中,他会悲观认为数据不会保持一致性,所以是会将相应的数据锁定。在数据库中,悲观锁的实现是依赖数据库提供的锁机制。

如果加上了悲观锁,那么就无法对这些数据进行读取操作。

2. 乐观锁

乐观锁对于数据库的数据的读写持乐观态度,即在整个数据处理的过程中,他会很乐观的认为数据会保持一致性,所以不加锁,而是通过数据版本记录机制实现。

MySQL中的MVCC多版本控制就是乐观锁的一种实现方式。

  • 往往会在数据表中增加一个类型version的版本号字段
  • 在查询数据库中的数据时,会将版本号字段的值一起读取出来。
  • 当更新数据时,会令版本号字段的值加1。将提交数据的版本与数据库表对应记录的版本进行对比。
  • 如果提交的数据版本号大于数据表中当前要修改的数据的版本号,则数据进行修改操作。
  • 否则不修改数据库表中的数据。

3. 读锁

读写又称为共享锁或者S锁(Shared Lock),针对同一份数据,可以加多个读锁而互不影响。

4. 写锁

写锁又称为排他锁或者X锁(Exclusive Lock),如果当前写锁未释放,他会阻塞其他的写锁和读锁。

5. 表锁

表锁也称为表级锁,就是在整个数据表上对数据进行加锁和释放锁。特点:开销小,加速快,粒度大,并发度最低,发生锁冲突概率高。

在MySQL中,有两种表锁模式:一种是表共享锁(Table Shard Lock),另一种是表独占写锁(Table Write Lock)

当一个线程获取到一个表的读锁后,其他线程仍然可以进行读操作,但不能对表进行写操作。那么对应的如果一个线程获取到一个表的写锁后,只有这个线程可以进行读写操作,其他线程无法对表进行读写操作,直到写锁被释放为止。

在mysql中可以通过以下命令手动添加表锁

代码语言:txt
复制
LOCKTABLE 表名称 read(write);  

eg: 添加读表锁

代码语言:txt
复制
LOCKTABLE user_table read;  

eg: 添加写表锁

代码语言:txt
复制
LOCKTABLE user_table write;  

使用如下命令可以查看数据表上增加的锁

代码语言:txt
复制
SHOWOPENTABLES;  

删除表锁:

代码语言:txt
复制
UNLOCKTABLES;  

6. 行锁

行锁也称为行级别,就是在数据行上对数据进行加锁和释放锁。特点:开销大,加锁慢,粒度小,并发度高,锁冲突概率最小。

在mysql的InnoDB存储引擎中有两种行锁,排他锁和共享锁。

  • 共享锁:允许一个事务读取一行数据,但不允许一个事务对加了共享锁的当前行增加排他锁
  • 排他锁:允许当前事务对数据行进行增删改查操作,不允许其他事务对增加了排他锁的数据行增加共享锁和排他锁

注意:

  1. 行锁主要加在索引上,如果对非索引字段设置条件进行更新,行锁可能会变成表锁。例如UPDATE user_table SET number = 2 WHERE name = 'fanone' 如果name没有加索引,那么可能会进行表锁。所以我们一般建议使用主键id作为更新数据的查询条件。
  2. InnoDB的行锁是针对索引加锁,不是针对记录加锁,并且加锁的索引不能失效,否则行锁也有可能变成表锁。而导致索引失效的有很多,比如联合索引不遵循最左匹配原则会失效、OR会失效等等...
  3. 锁定某一行时,可以使用lock in share mode命令来指定共享锁,使用for update命令来指定排他锁。
代码语言:txt
复制
UPDATE user_table SETnumber = 2WHEREname = 'fanone'LOCKINSHAREMODE;
UPDATE user_table SETnumber = 2WHEREname = 'fanone'FORUPDATE;  

7. 页面锁

页级锁定是 MySQL 中比较独特的一种锁定级别。特点:锁定颗粒度介于行级锁定与表级锁之间,锁开销和加锁时间界于表锁和行锁之间,并发处理能力也同样是介于上面二者之间,并发度一般。

不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。

使用页级锁定的主要是 BerkeleyDB 存储引擎。

8. 间隙锁

在mysql中使用范围查询的时,如果请求共享锁或者排他锁,InnoDB会给符合条件的已有数据的索引项加锁。如果键值在条件范围内,而这个范围内并不存在记录,而认为此时出现了间隙,InnoDB会对这个间隙进行加锁,这也称为间隙锁。

eg:

代码语言:txt
复制
SELECT * FROM user_user;
+----+-------+-------+
|id  |  name |  sex  |
+----+-------+-------+
| 1  |zhangsan| 1    |
| 2  |lisi    | 2    |
| 3  |lisi2   | 2    |
| 7  |lisi3   | 2    |
| 10 |lisi4   | 2    |
| 21 |lisi5   | 2    |
+----+-------+-------+

上面出现了间隙有 (3,7], (7,10], (10,21],(21,+∞] 的三个区间。

如果执行以下sql

代码语言:txt
复制
UPDATE user_user SET sex = 1WHEREid > 8ANDid < 18;  

那么其他事务就无法在 (7,21] 这个区间内插入或者修改任何数据。间隙锁会锁住 (7,10], (10,21] 这两个间隙。不过间隙锁只会在 可重复读事务隔离级别 下才会生效。

9. 临键锁

临键锁就是行锁和间隙锁的组合,也可以理解为一种特殊的间隙锁。通过临建锁可以解决幻读的问题。

每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据

需要强调的一点是,InnoDB 中行级锁是基于索引实现的,临键锁只与非唯一索引列有关 ,在唯一索引列(包括主键列)上不存在临键锁。

上面的(7,21]就是临键锁。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MySQL锁总体结构
    • 1. 悲观锁
      • 2. 乐观锁
        • 3. 读锁
          • 4. 写锁
            • 5. 表锁
              • 6. 行锁
                • 7. 页面锁
                  • 8. 间隙锁
                    • 9. 临键锁
                    相关产品与服务
                    云数据库 MySQL
                    腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档