夜间模式
锁
锁机制是用于管理多个用户对数据库资源(如表或行)的并发访问的关键部分。
锁的设计目的是为了保护数据的一致性和完整性,同时尽量提高并发性能。
不同的存储引擎支持不同类型的锁,以下是 MySQL 锁机制的详细说明:
1. 锁的分类
按锁的粒度分类
全局锁
锁住整个数据库实例,适用于备份等场景。
使用命令:
FLUSH TABLES WITH READ LOCK
(FTWRL)。特性:
- 阻止对数据库的写入操作(只读模式)。
- 不适合高并发场景,会阻塞所有事务。
示例:
sqlFLUSH TABLES WITH READ LOCK; -- 解锁: UNLOCK TABLES;
1
2
3
表级锁
锁住整个表,适用于简单操作。
类型:
- 读锁(共享锁,S 锁):多个会话可同时读取。
- 写锁(排他锁,X 锁):阻止其他会话的读写。
使用:
LOCK TABLES
和UNLOCK TABLES
。示例:
sqlLOCK TABLES table_name READ; UNLOCK TABLES;
1
2
行级锁
锁住特定的行,粒度更细,适用于高并发事务。
常见于支持事务的存储引擎(如 InnoDB)。
示例:
sqlSELECT * FROM table_name WHERE id = 1 FOR UPDATE;
1
2
按锁的模式分类
共享锁(S 锁,读锁)
允许多个事务读取同一资源,但不允许修改。
示例:
sqlSELECT * FROM table_name WHERE id = 1 LOCK IN SHARE MODE;
1
2
排他锁(X 锁,写锁)
一个事务持有排他锁时,其他事务不能读取或修改该资源。
示例:
sqlSELECT * FROM table_name WHERE id = 1 FOR UPDATE;
1
2
意向锁(Intent Lock)
- 表级锁,用于标记事务即将在某些行上加锁。
- 仅适用于 InnoDB,帮助协调表级锁和行级锁之间的冲突。
- 类型:
- 意向共享锁(IS 锁):事务打算加 S 锁。
- 意向排他锁(IX 锁):事务打算加 X 锁。
间隙锁(Gap Lock)
锁住一个范围(而非具体行),用于防止幻读。
示例:
sqlSELECT * FROM table_name WHERE id BETWEEN 10 AND 20 FOR UPDATE;
1
2
2. 不同存储引擎的锁特性
InnoDB
- 支持 行级锁 和 表级锁。
- 默认使用行级锁,事务级操作更加灵活。
- 支持意向锁和间隙锁,用于事务隔离。
MyISAM
- 仅支持 表级锁。
- 读操作会加读锁(允许并发读)。
- 写操作会加写锁(阻止其他读写操作)。
MEMORY
- 默认使用表级锁。
- 由于数据存储在内存中,操作速度非常快,但并发性有限。
3. 锁的应用场景
全局锁应用场景
全库备份:避免备份过程中有写入操作导致数据不一致。
示例:
sqlFLUSH TABLES WITH READ LOCK;
1
2
表级锁应用场景
- 数据修复或全表操作。
- 需要避免其他线程对表的干扰。
行级锁应用场景
- 高并发事务:如在线交易系统。
- 需要更精细的锁粒度以减少锁冲突。
4. 事务隔离级别与锁
MySQL 提供了 4 种事务隔离级别,不同隔离级别会影响锁的使用。
- READ UNCOMMITTED(未提交读)
- 不加锁,可能读到未提交的数据(脏读)。
- READ COMMITTED(已提交读)
- 每次读取最新已提交数据。
- 加共享锁(S 锁)避免读冲突。
- REPEATABLE READ(可重复读,InnoDB 默认)
- 防止幻读,通过行锁和间隙锁实现。
- SERIALIZABLE(可串行化)
- 加共享锁或排他锁,强一致性但并发性能最低。
5. 锁的常见问题
- 死锁
- 两个或多个事务相互等待释放资源,造成死锁。
- 解决方法:
- 使用一致的锁顺序。
- 控制事务的粒度和长度。
- MySQL 的 InnoDB 引擎支持死锁自动检测。
- 锁等待
- 事务等待其他事务释放锁导致性能问题。
- 解决方法:
- 增加超时时间:
SET innodb_lock_wait_timeout = 10;
- 优化查询逻辑。
- 增加超时时间:
- 长时间锁定
- 长事务未提交或未释放锁,影响并发性能。
- 解决方法:
- 尽量缩短事务的时间。
- 手动释放锁:
ROLLBACK
或COMMIT
。
6. 查看和管理锁
查看当前锁状态
使用系统表 INFORMATION_SCHEMA.INNODB_LOCKS
和 INNODB_LOCK_WAITS
:
sql
-- 查看当前锁信息
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
-- 查看锁等待情况
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
1
2
3
4
5
2
3
4
5
手动管理锁
释放锁:
UNLOCK TABLES
或ROLLBACK
。设置锁超时:
sqlSET innodb_lock_wait_timeout = 5;
1
2
总结
MySQL 锁机制提供了多种粒度和模式,可以满足不同的并发控制需求。选择合适的锁类型和优化事务逻辑,是提高数据库性能和一致性的关键。