MySQL 的事务隔离级别

2025/06/04

Categories: 技术 Tags: MySQL

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再次查询发现多出数据。解决的方案有两种:

这两个解决方案是很大程度上解决了幻读现象,但是还是有个别的情况造成的幻读现象是无法解决的。

串行化(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 返回值分别是什么。

相关问题

MySQL 事务的特性(ACID)如何保证?

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;

参考资料