事务隔离级别

总结

介绍事务的四种隔离级别。

简介

在文章 并发事务引入的问题:幻读、不可重复读、脏读 中,已经指出:多个事务并发执行的时候,会引发脏读、不可重复读、幻读这些问题。为了避免这些问题,SQL 标准提出了四种隔离级别:

  • 分别是读未提交、读已提交、可重复读、串行化,从左往右隔离级别顺序递增,隔离级别越高,也意味着性能越差。
  • 隔离级别的主要目的是平衡数据的一致性和系统的并发性。

InnoDB 引擎的默认隔离级别是可重复读。
不同的数据库厂商对隔离级别的支持不一样,有的数据库只实现了其中几种隔离级别;MySQL 支持 4 种隔离级别,但是与 SQL 标准中规定的各级隔离级别允许发生的现象却有些出入。

概念

四种事务隔离级别

  • READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、不可重复读、幻读。
  • READ-COMMITTED(读取已提交) :允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
  • REPEATABLE-READ(可重复读) :对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化):最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,事务之间完全不可能产生干扰,该级别可以防止脏读、不可重复读以及幻读。但是可能导致大量的超时和锁争用,实际应用中很少用到这个隔离级别。

表格对比

隔离级别 是否允许脏读 是否允许不可重复读 是否允许幻读
读未提交(Read Uncommitted)
读已提交(Read Committed)
可重复读(Repeatable Read) ❌ / ✅(取决于数据库实现)
串行化(Serializable)

MySQL 的 InnoDB 引擎在“可重复读”级别通过间隙锁(Gap Lock)解决了幻读问题。

举例说明

假设有两个并发的事务,事务 M 修改值,事务 N 进行查询,下面是按照时间顺序执行两个事务的行为:

事务 M 事务 N
A 本来是 1
begin; begin;
update A=2;
select A;第 1 次读 A
commit;
select A;第 2 次读 A
commit;
select A;第 3 次读 A

在不同隔离级别下,事务N 执行过程中查询到的值可能会不同,记三次查询的值为 V1~V3:

  • 读未提交隔离级别:V1=2,余额 V2、V3 也是 2 ;
  • 读已提交隔离级别下:V1=1,V2、V3 都是 2;
  • 可重复读隔离级别下:V1、V2 都是 1, V3 =2;
  • 串行化隔离级别下:事务 M 提交后,事务 N 才可以执行, V1、V2、V3= 2。

相关语句

  • 查看当前会话隔离级别
select @@tx_isolation;

-- MySQL 8.0中只能用以下语句
SELECT @@transaction_isolation;
  • 查看系统隔离级别
select @@global.tx_isolation;
  • 设置当前会话隔离级别(新的隔离级别会在下一个事务开始的时候生效)
set session transaction isolatin level repeatable read;
  • 设置系统隔离级别(新的隔离级别会在下一个事务开始的时候生效)
set global transaction isolation level repeatable read;

关联文章


文章作者: huan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 huan !
  目录