MySQL 锁

锁的基本概念与分类

1. 什么是锁?

锁是数据库实现并发控制的核心手段,能够确保多人同时操作数据库时,数据的一致性和完整性不受破坏,保障系统正常运行。

2. MySQL 支持的锁类型

MySQL 提供三类核心锁,不同存储引擎对锁的支持存在差异:

锁类型 说明 支持存储引擎
全局锁 对整个数据库实例加锁,使数据库进入只读状态 所有存储引擎
表级锁 对整张数据表加锁,锁定粒度较大 InnoDB、MyISAM
行级锁 对单个行记录加锁,锁定粒度最小 InnoDB

死锁相关问题

1. 什么是死锁?

死锁是指两个或多个进程在执行过程中,因相互争夺资源而陷入互相等待的状态,若无外力干预,所有进程都无法继续推进,导致事务阻塞。

2. 死锁的处理方式

  • 超时等待:通过 innodb_lock_wait_timeout 参数设置超时时间(默认 50s),事务等待超时后自动释放资源。

  • 死锁检测(默认开启):设置 innodb_deadlock_detect = on,数据库会主动检测死锁,发现后回滚其中一个事务,确保其他事务正常执行。

3. 死锁的查看方式

  • 执行命令 show engine innodb status,可查看最近一次死锁的详细信息。

  • 开启 InnoDB Lock Monitor 锁监控,系统每 15s 输出一次锁相关日志;使用完毕后建议关闭,避免占用过多资源影响数据库性能。

4. 死锁检测的开启

innodb_deadlock_detect 参数默认值为 on,即默认开启死锁检测;若已关闭,可通过修改该参数重新开启。

5. InnoDB 对死锁的默认处理

InnoDB 默认采用超时策略处理死锁,innodb_lock_wait_timeout 参数默认时长为 50s,超时后阻塞的事务会被终止。

全局锁

1. 什么是全局锁?

全局锁是对整个数据库实例施加的锁,加锁后数据库进入只读状态,数据更新语句、数据定义语句、更新类事务的提交语句等操作都会被阻塞。

2. 应用场景

典型场景为全库逻辑备份,通过加全局锁确保备份过程中数据的一致性。

3. 设置方式

执行命令 flush tables with read lock(简称 FTWRL),即可为数据库添加全局只读锁。

4. 潜在问题

  • 主库备份:备份期间无法执行更新操作,导致业务停摆。

  • 从库备份:备份期间无法同步主库的 binlog 日志,引发主从延迟。

5. 其他设置只读的方式

除 FTWRL 外,还可通过命令 set global readonly=true 将数据库设置为只读状态。

6. FTWRL 与 set global readonly=true 的区别

两者核心区别在于客户端断开后的行为:

  • FTWRL:客户端断开连接后,数据库会自动取消只读状态。

  • set global readonly=true:客户端断开后,数据库仍保持只读状态,需手动修改参数恢复。

共享锁与排他锁

1. 共享锁(读锁,read lock)

  • 定义:由读取操作创建的锁,支持并发读。

  • 特性:多个事务可同时对同一数据添加共享锁;加锁期间,任何事务无法修改数据(即无法获取排他锁),需等待所有共享锁释放。

2. 排他锁(写锁,writer lock)

  • 定义:由写操作相关的事务创建的锁,是悲观锁的一种实现。

  • 特性:某事务对数据加排他锁后,仅该事务可对数据执行写操作;其他事务可读取数据,但无法执行写操作,也不能添加任何锁,需等待排他锁释放。

3. 锁的手动添加方式

  • 共享锁:执行 SELECT … LOCK IN SHARE MODE,MySQL 会对查询结果集中的每行添加共享锁(前提:当前线程未对结果集中的行使用排他锁,否则申请会阻塞)。

  • 排他锁:执行 SELECT ... FOR UPDATE,MySQL 会对查询结果集中的每行添加排他锁;事务中对记录的更新、删除操作会自动添加排他锁(前提:当前无其他线程对结果集中的行使用排他锁或共享锁,否则申请会阻塞)。

InnoDB 存储引擎的锁算法与行锁实现

1. 锁算法类型

InnoDB 提供三种锁算法,用于实现不同粒度的锁定:

  • Record Lock:单个行记录上的锁,锁定粒度最小。

  • Gap Lock:间隙锁,锁定一个数据范围,不包含范围边界的记录本身。

  • Next-Key Lock:锁定一个数据范围,包含范围边界的记录本身(默认锁算法)。

2. 行锁的实现

行级锁是 MySQL 中粒度最小的锁,能最大程度减少并发操作的冲突,其实现依赖上述锁算法,具体通过共享锁和排他锁的添加逻辑实现(详见“共享锁与排他锁”章节)。

逻辑备份的优化方案

使用全局锁备份会导致数据库无法插入数据,官方提供的 mysqldump 工具可解决该问题:

在执行备份时添加参数 -single-transaction,工具会在导入数据前启动一个事务,通过事务的隔离性保证数据一致性,同时支持备份期间的数据更新操作。