如何理解mysql 的事务隔离级别 repeatable read
在MySQL中,事务隔离级别定义了事务之间如何相互隔离,以及数据的一致性和并发性如何平衡。REPEATABLE READ
(可重复读)是MySQL中四种事务隔离级别之一,它在保证数据一致性的同时,允许较高的并发性。
MySQL的四种事务隔离级别
- READ UNCOMMITTED(未提交读)
- READ COMMITTED(提交读)
- REPEATABLE READ(可重复读)
- SERIALIZABLE(可串行化)
这四种隔离级别从低到高分别提供了不同程度的数据一致性和并发控制。
REPEATABLE READ
的特性
在 REPEATABLE READ
隔离级别下,事务在执行 SELECT
语句时,会看到在该事务开始时存在的数据状态。这意味着在同一个事务中多次读取同一行数据,结果是相同的,即使其他事务已经对数据进行了修改并提交。这种行为防止了不可重复读(non-repeatable read),即在同一事务中多次读取同一行数据得到不同结果的问题。
为了更好地理解 REPEATABLE READ
,需要理解以下几个关键概念:
1. 多版本并发控制(MVCC)
MySQL的InnoDB存储引擎通过使用MVCC实现 REPEATABLE READ
。MVCC允许事务在读取数据时,不需要加锁,从而提高并发性能。每行数据有多个版本,事务读取的数据版本是在事务开始时的数据快照(snapshot)。这种机制使得读取操作不会阻塞写入操作,反之亦然。
2. 快照读(Snapshot Read)
在 REPEATABLE READ
隔离级别下,普通的 SELECT
语句是快照读。快照读从事务开始时的快照读取数据,不会受到其他事务修改数据的影响。
3. 当前读(Current Read)
SELECT ... FOR UPDATE
和 SELECT ... LOCK IN SHARE MODE
语句是当前读。当前读读取的是最新的数据,并且会锁定读取的数据行以防止其他事务修改。这种读方式用于需要对数据进行后续修改的场景。
4. 幻读(Phantom Read)
REPEATABLE READ
隔离级别还解决了幻读问题。幻读是指在同一事务中两次执行相同的查询,但结果集不一致的问题。例如,在第一次查询时没有新插入的行,但在第二次查询时有其他事务插入了新行。InnoDB通过间隙锁(Gap Lock)和Next-Key锁机制解决了幻读问题。
示例
假设有一个表 employees
,结构如下:
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
salary DECIMAL(10, 2)
);
事务A:
START TRANSACTION;
SELECT * FROM employees WHERE id = 1;
-- 返回结果:{ id: 1, name: 'John', salary: 5000.00 }
事务B:
START TRANSACTION;
UPDATE employees SET salary = 6000.00 WHERE id = 1;
COMMIT;
事务A:
SELECT * FROM employees WHERE id = 1;
-- 仍然返回结果:{ id: 1, name: 'John', salary: 5000.00 }
COMMIT;
在事务A中,即使事务B已经提交了更新,事务A在第二次读取时依然看到的是事务开始时的数据快照。
也就是说REPEATABLE READ
隔离级别通过MVCC机制,确保在一个事务中多次读取相同数据时结果一致,防止了不可重复读和幻读问题,同时在不锁定数据的情况下允许较高的并发性。这种隔离级别是MySQL InnoDB存储引擎的默认隔离级别,适用于大多数应用场景,在提供数据一致性的同时,具有较好的并发性能。