MySQL的事务隔离作用是确保事务之间的操作相互隔离,避免数据不一致问题,从而保证数据库的一致性和并发事务的正确执行。
它定义了多个并发事务如何看到彼此的数据变更。其核心作用在于解决并发事务操作同一数据时可能引发的数据一致性问题,确保每个事务都像是在独立运行的环境中操作数据。
并发事务会导致的问题
脏读
事务读取到其他事务尚未提交的无效数据。例如,事务 A 修改数据但未提交,事务 B 读取该数据后若A回滚,则 B 读到的是脏数据。
不可重复读
同一事务内多次读取同一数据,因其他事务提交了修改导致结果不一致。例如,事务 A 读取某行数据后,事务 B 更新并提交该行,A 再次读取时数据变化。
幻读
事务按条件查询数据时,其他事务插入符合条件的新数据并提交,导致当前事务再次查询时出现“幻影”记录。例如,事务 A 查询年龄 =20 的记录,事务 B 插入一条年龄 =20 的新记录并提交,A 再次查询时会多出一条数据。
事务隔离级别
多个事务并发执行时,可能会导致上述的问题,对事务的一致性产生不同程度的影响,SQL 标准提出了四种隔离级别来规避这些问题,隔离级别越高性能效率越低,隔离级别由低到高分别为:
读未提交(READ UNCOMMITTED)
最低的隔离级别,允许事务读取其他事务尚未提交的数据变更。
这可能导致脏读、不可重复读或幻读问题。例如,事务A修改数据但未提交,事务B读取该数据后若A回滚,则B读到的是无效数据(脏读)。
读已提交(READ COMMITTED)
此级别解决了脏读问题,但可能出现不可重复读和幻读。
例如,同一事务内多次读取同一数据,结果因其他事务提交而不同。
可重复读(REPEATABLE READ)
保证同一事务内多次读取相同数据的结果保持一致,避免脏读和不可重复读,但理论上仍可能遇到幻读。
例如,事务A读取符合条件的数据,事务B插入新数据并提交后,A再次查询发现多出数据。解决的方案有两种:
- 针对快照读(普通 SELECT 语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。
- 针对当前读(SELECT … FOR UPDATE 等语句),是通过 Next-key Lock(记录锁+间隙锁)方式解决了幻读,因为当执行该语句的时候,会加上 Next-key Lock,如果有其他事务在锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
这两个解决方案是很大程度上解决了幻读现象,但是还是有个别的情况造成的幻读现象是无法解决的。
串行化(SERIALIZABLE)
最高的隔离级别,强制事务串行执行,完全隔离并发操作,避免脏读、不可重复读和幻读。
但会显著降低数据库性能,仅在严格要求数据一致性时使用。
场景举例
CREATE TABLE `T` (`value` int) ENGINE=InnoDB;
INSERT INTO `T` (`value`) VALUES (1);
| 操作步骤 | 事务 A | 事务 B |
|---|---|---|
| 1 | 启动事务,得到值 1 | 开启事务 |
| 2 | 查询得到值 1 | |
| 3 | 将 1 改成 2 | |
| 4 | 查询得到值 V1 | |
| 5 | 提交事务 B | |
| 6 | 查询得到值 V2 | |
| 7 | 提交事务 A | |
| 8 | 查询得到值 V3 |
在不同的隔离级别下,事务 A 中的 V1、V2、V3 返回值分别是什么。
- 若隔离级别为『读未提交』,则 V1=2、V2=2、V3=2;操作 4 可以读取到事务B的修改,所以 V1 为修改后的值。
- 若隔离级别为『读已提交』,则 V1=1、V2=2、V3=2;操作 6 可以读取到事务B提交后的值,所以 V2 为修改后的值。
- 若隔离级别为『可重复读』,则 V1=1、V2=1、V3=2;操作 4 和 6 在事务执行期间读取的值前后一致,为 V1 时读取到的值 1。
- 若隔离级别为『串行化』,则 V1=1、V2=1、V3=2;事务 B 在操作 3 时会被阻塞住,直到事务 A 提交后才可继续执行,所以 V1、V2的值是 1。
相关问题
MySQL 事务的特性(ACID)如何保证?
-
原子性(Atomicity)
- 定义:事务是一个不可分割的最小操作单元,其包含的所有操作要么全部成功,要么全部失败回滚。
- 如何保证:MySQL 通过 Undo Log(撤销日志)实现原子性。
-
一致性(Consistency)
- 定义:事务执行前后,数据库的完整性约束(如主键、外键、触发器等)始终有效,数据处于合法状态。
- 如何保证:一致性依赖原子性、隔离性和持久性的共同保障。
-
隔离性(Isolation)
- 定义:多个事务并发执行时,彼此隔离,避免相互干扰导致的数据异常(如脏读、不可重复读、幻读)。
- 如何保证:MySQL 通过锁机制和多版本并发控制(MVCC)实现隔离性。
- 通过设置隔离级别(如可重复读、串行化)进一步控制并发行为。
-
持久性(Durability)
- 定义:事务一旦提交,其对数据库的修改是永久性的,即使系统崩溃也不会丢失。
- 如何保证:MySQL 通过 Redo Log(重做日志)和双写缓冲(Doublewrite Buffer)实现持久性。
MySQL 如何查看和设置事务隔离级别?
隔离级别查看:
-- MySQL 8.0 之前
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
-- MySQL8.0
SELECT @@global.transaction_isolation;
SELECT @@session.transaction_isolation;
SELECT @@transaction_isolation;
隔离级别设置,参考官方手册:
-- SET [GLOBAL | SESSION] TRANSACTION
-- transaction_characteristic [, transaction_characteristic] ...
-- transaction_characteristic: {
-- ISOLATION LEVEL level
-- | access_mode
-- }
-- level: {
-- REPEATABLE READ
-- | READ COMMITTED
-- | READ UNCOMMITTED
-- | SERIALIZABLE
-- }
-- access_mode: {
-- READ WRITE
-- | READ ONLY
-- }
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;