外观
MySQL 事务管理与隔离级别
事务基础
事务概念
事务是数据库操作的基本单位,具有原子性、一致性、隔离性和持久性(ACID)特性:
- 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败回滚
- 一致性(Consistency):事务执行前后数据库状态保持一致
- 隔离性(Isolation):多个事务并发执行时互不干扰
- 持久性(Durability):事务提交后,数据永久保存到磁盘
事务生命周期
- 开始事务:使用START TRANSACTION或BEGIN命令
- 执行SQL语句:执行各种DML和DDL语句
- 提交事务:使用COMMIT命令,将更改永久保存
- 回滚事务:使用ROLLBACK命令,撤销所有更改
- 自动提交:默认情况下,MySQL自动提交每个SQL语句
事务控制语句
sql
-- 开始事务
START TRANSACTION;
-- 或
BEGIN;
-- 执行SQL语句
INSERT INTO table_name VALUES (value1, value2);
UPDATE table_name SET column1 = value1 WHERE condition;
-- 提交事务
COMMIT;
-- 回滚事务
ROLLBACK;
-- 设置保存点
SAVEPOINT savepoint_name;
-- 回滚到保存点
ROLLBACK TO SAVEPOINT savepoint_name;
-- 删除保存点
RELEASE SAVEPOINT savepoint_name;隔离级别
隔离级别类型
MySQL支持以下四种隔离级别:
- 读未提交(READ UNCOMMITTED):允许读取未提交的数据,可能导致脏读、不可重复读和幻读
- 读已提交(READ COMMITTED):只允许读取已提交的数据,避免脏读,但可能导致不可重复读和幻读
- 可重复读(REPEATABLE READ):确保同一事务中多次读取同一数据结果一致,避免脏读和不可重复读,但可能导致幻读
- 串行化(SERIALIZABLE):最高隔离级别,完全串行执行事务,避免所有并发问题,但性能最低
隔离级别比较
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 并发性 |
|---|---|---|---|---|
| 读未提交 | 是 | 是 | 是 | 最高 |
| 读已提交 | 否 | 是 | 是 | 高 |
| 可重复读 | 否 | 否 | 否 | 中 |
| 串行化 | 否 | 否 | 否 | 最低 |
隔离级别设置
全局设置
sql
-- 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;会话设置
sql
-- 设置当前会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;查看隔离级别
sql
-- 查看全局隔离级别
SELECT @@GLOBAL.tx_isolation;
-- 或
SELECT @@GLOBAL.transaction_isolation;
-- 查看当前会话隔离级别
SELECT @@SESSION.tx_isolation;
-- 或
SELECT @@SESSION.transaction_isolation;并发问题
脏读(Dirty Read)
- 定义:读取到其他事务未提交的数据
- 示例:事务A修改数据但未提交,事务B读取到该未提交的数据,事务A回滚,事务B读取到的数据无效
- 避免方法:使用READ COMMITTED或更高隔离级别
不可重复读(Non-repeatable Read)
- 定义:同一事务中多次读取同一数据,结果不一致
- 示例:事务A读取数据,事务B修改数据并提交,事务A再次读取同一数据,结果不同
- 避免方法:使用REPEATABLE READ或SERIALIZABLE隔离级别
幻读(Phantom Read)
- 定义:同一事务中多次查询同一范围的数据,结果集行数不同
- 示例:事务A查询满足条件的记录数,事务B插入或删除满足条件的记录并提交,事务A再次查询,结果集行数不同
- 避免方法:使用SERIALIZABLE隔离级别,或在InnoDB中使用REPEATABLE READ隔离级别结合间隙锁
锁机制
锁类型
共享锁(Shared Lock)
- 也称为读锁
- 允许多个事务同时读取同一资源
- 不允许其他事务获取排它锁
- 使用方式:SELECT ... LOCK IN SHARE MODE
排它锁(Exclusive Lock)
- 也称为写锁
- 只允许一个事务持有排它锁
- 不允许其他事务获取共享锁或排它锁
- 使用方式:SELECT ... FOR UPDATE,或DML语句自动获取
锁粒度
表级锁
- 锁定整个表
- 开销小,加锁快
- 并发度低
- MyISAM存储引擎默认使用
行级锁
- 锁定单行数据
- 开销大,加锁慢
- 并发度高
- InnoDB存储引擎默认使用
页级锁
- 锁定一页数据
- 开销和并发度介于表级锁和行级锁之间
- 少数存储引擎支持
锁算法
记录锁(Record Lock)
- 锁定单行记录
- 基于索引记录
间隙锁(Gap Lock)
- 锁定索引记录之间的间隙
- 防止插入幻影记录
- 只在REPEATABLE READ和SERIALIZABLE隔离级别下使用
临键锁(Next-Key Lock)
- 记录锁和间隙锁的组合
- 锁定记录及前面的间隙
- InnoDB默认的行锁算法
死锁
死锁概念
两个或多个事务互相等待对方释放锁资源,导致所有事务无法继续执行
死锁检测
- MySQL自动检测死锁
- 选择回滚代价最小的事务
- 可以通过配置参数innodb_deadlock_detect启用或禁用
死锁避免
- 保持事务简短,减少锁持有时间
- 按相同顺序访问表和行
- 避免长时间事务
- 使用合理的索引,减少锁范围
- 考虑使用更低的隔离级别
MVCC(多版本并发控制)
MVCC概念
MVCC是一种并发控制机制,允许读取操作在不阻塞写入操作的情况下执行,写入操作在不阻塞读取操作的情况下执行
MVCC实现原理
- 为每行数据保存多个版本
- 使用事务ID标识不同版本
- 读取操作只读取事务开始前已提交的数据版本
- 写入操作创建新的数据版本
MVCC优势
- 提高并发性能
- 减少锁竞争
- 允许非阻塞读取
- 支持不同隔离级别
MVCC在不同隔离级别下的表现
- 读未提交:忽略版本信息,读取最新数据
- 读已提交:读取事务开始时的最新已提交版本
- 可重复读:读取事务开始时的快照
- 串行化:使用锁机制,不使用MVCC
事务优化
事务设计优化
- 保持事务简短,减少锁持有时间
- 避免在事务中执行耗时操作
- 尽量减少事务中的SQL语句数量
- 合理使用保存点
隔离级别优化
- 根据业务需求选择合适的隔离级别
- 优先使用READ COMMITTED或REPEATABLE READ
- 避免使用SERIALIZABLE,除非必要
锁优化
- 使用合理的索引,减少锁范围
- 避免全表扫描
- 考虑使用乐观锁替代悲观锁
- 合理设置锁超时时间
并发控制优化
- 使用连接池管理连接
- 优化查询语句,减少执行时间
- 考虑使用读写分离
- 实现数据分片,分散并发压力
常见问题(FAQ)
Q1:MySQL默认隔离级别是什么?
A1:MySQL默认隔离级别是REPEATABLE READ,这是InnoDB存储引擎的默认设置。
Q2:如何查看当前事务隔离级别?
A2:可以使用SELECT @@SESSION.transaction_isolation;命令查看当前会话的隔离级别。
Q3:什么是脏读、不可重复读和幻读?
A3:脏读是读取未提交的数据;不可重复读是同一事务中多次读取同一数据结果不同;幻读是同一事务中多次查询同一范围的数据结果集行数不同。
Q4:如何避免死锁?
A4:可以通过保持事务简短、按相同顺序访问表和行、避免长时间事务、使用合理的索引等方式避免死锁。
Q5:MVCC是什么?它有什么优势?
A5:MVCC是多版本并发控制,允许读取操作和写入操作并发执行,提高并发性能,减少锁竞争。
Q6:如何优化事务性能?
A6:可以通过保持事务简短、选择合适的隔离级别、优化锁使用、使用连接池等方式优化事务性能。
Q7:事务提交后可以回滚吗?
A7:事务提交后,数据已经永久保存到磁盘,无法回滚。
Q8:MySQL支持哪些事务控制语句?
A8:MySQL支持START TRANSACTION/BEGIN、COMMIT、ROLLBACK、SAVEPOINT、ROLLBACK TO SAVEPOINT和RELEASE SAVEPOINT等事务控制语句。
