Skip to content

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支持以下四种隔离级别:

  1. 读未提交(READ UNCOMMITTED):允许读取未提交的数据,可能导致脏读、不可重复读和幻读
  2. 读已提交(READ COMMITTED):只允许读取已提交的数据,避免脏读,但可能导致不可重复读和幻读
  3. 可重复读(REPEATABLE READ):确保同一事务中多次读取同一数据结果一致,避免脏读和不可重复读,但可能导致幻读
  4. 串行化(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等事务控制语句。