写点什么

MySQL 的锁 (一)

作者:技术小生
  • 2022 年 7 月 19 日
  • 本文字数:1241 字

    阅读完需:约 4 分钟

写在前面

其实 MySQL 中存在各种各样的锁,但其实由于分类的标准不一样,说法也各有不同。我在这篇文章中介绍的 MySQL 的锁是以锁的粒度区分的。

MySQL 的锁种类

全局锁

对整个数据库实例加锁,命令是 Flush tables with read lock。使这个库处于只读状态,数据更新语句(DML)、数据定义语句(DDL)以及更新类事务的提交语句都会被阻塞。

全局锁的典型应用场景是做全库逻辑备份,官方自带的逻辑备份工具 mysqldump。

mysqldump 使用-single-transaction 的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。由于 MVCC 的支持,这个过程数据是可以正常更新。

mysqldump 中重要的点(只适用于使用 innoDB 引擎的库):

  1. FLUSH /*!40101 LOCAL */ TABLES


  1. FLUSH TABLES WITH READ LOCK

执行完 1,再执行 2 的目的就是为了避免长事务操作造成 FLUSH TABLES WITH READ LOCK 操作获取不到锁,同时又阻塞其他客户端的操作。

  1. SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ

设置当前事务的事务隔离级别为 RR,避免不可重复读和幻读。

  1. START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */

start transaction 和 start transaction with consistent snapshot 区别

1)start transaction  时,是第一条语句的执行时间点,就是事务开始的时间点,第一条 select 语句建立一致性读的 snapshot;

2)start transaction with consistent snapshot 时,

则是立即建立本事务的一致性读 snapshot,同时开启事务

  1. UNLOCK TABLES

释放全局锁

为什么不使用 set global readonly=true 的方式使全库只读?

  • readonly 参数用于主从库判断逻辑使用

  • 全局锁在客户端发生异常后,会自动释放;而将整个库设置成 readonly,会导致整个库不可写

表级锁

  • 表锁

语法:lock tables XXX read/write

  • 元数据锁(MetaData Lock)

MDL 不需要显式使用,在访问表的时候会被自动加上。

MySQL5.5 引入 MDL,当对一个表做增删改查操作时,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。(读锁之间不互斥;读写锁和写锁之间是互斥的)


如何安全地给表加字段?

解决事务占据 MDL 读锁不释放的问题;alter table 里面设定等待时间,避免事务阻塞。

行级锁

innoDB 行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,innoDB 才使用行锁,否则使用表级锁。

在 innoDB 事务中,行锁是在需要的时候才加上,在事务结束时才释放的。可以提供较高的并发,但存在死锁问题-----两阶段锁协议:如果事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

一次性锁协议:在事务开始时,一次性申请所有的锁。在事务结束时,一次性释放所有的锁。不存在死锁问题。


出现死锁的解决策略:

  • 直接进入等待,直到超时。由 innodb_lock_wait_timeout 设置

  • 主动发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。由 innodb_deadlock_detect 设置,为 on 表示开启死锁检测。

总结

相信大家还听说过 MySQL 其他的锁,比如乐观锁、悲观锁、间隙锁等。其他这就是另外的分类标准了。我也会在后续详细介绍。

发布于: 刚刚阅读数: 3
用户头像

技术小生

关注

业务应用架构专家 2019.10.08 加入

主要负责公司内部系统的应用架构设计与落地。擅长Java语言开发,熟悉Python、Shell等。精通K8S等云原生相关技术。

评论

发布
暂无评论
MySQL的锁(一)_MySQL_技术小生_InfoQ写作社区