事务隔离级别

本文主要为了总结事务隔离级别的整体知识,包含模拟脏读、不可重复读和幻读的场景

1. 什么是事务隔离级别?

什么是事务?

要了解什么是事务隔离级别,需要先了解什么事务,可参考 百度百科-数据库事务 的概念解释,简单来说:

数据库事务,描述的是对数据库进行读写操作的一个操作序列,要么全部执行,要么全都不执行的现象,这个操作序列是原子性的、不可分割的工作单元

并且数据库事务包含如下 4 个经典特性,也就是常说的 ACID 特性:

  • 原子性(Atomicity)

    事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行

  • 一致性(Consistency)

    几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致

    也就是说,当执行数据库事务操作后(事务提交或者事务回滚),数据库的完整性约束不能被破坏

  • 隔离性(Isolation)

    事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的

  • 持久性(Durability)

    对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障

为什么要有事务隔离级别?

数据库的事务经常需要并发执行,也即经常会有多个客户端连接到数据库上来进行读写操作,并发事务下会发生如下几种问题:

  • 丢失更新,包含回滚丢失和覆盖丢失两种

    可参考:并发事务导致的丢失更新及处理方式详解 博文进行了解

  • 脏读

    某个事务读到了其他事务还没有提交的数据

  • 不可重复读

    着重指针对某一行数据,在同一个事务内多次读取的内容不同,同一条记录的内容被修改了(或删除了)

    产生原因:读取过程中,有其他事务对该数据进行了修改或删除

  • 幻读, 参见 mysql-官网-幻读说明

    着重指在同一个事务里的操作发现了未被操作的数据

    比如,事务 A 根据条件查询得到了 N 条数据,准备进行更新操作;但此时事务 B 新增或删除了 M 条符合事务 A 查询条件的的数据;当事务 A 执行更新操作,重新查询后发现了 M 条自己不应该进行更新的记录,就像发生了幻觉一样

    注意,上述示例的事务 A 的查询得到 N 条数据,准备更新这 N 条数据,并重新根据条件进行查询的操作均在同一个事务内

其中,丢失更新的问题是由于临界资源使用不当造成(同一条数据被并发修改,该条数据应被视为共享临界资源,需要使用者控制好加锁方式),可通过加锁方式来解决

而脏读、不可重复读和幻读,则需要通过事务隔离级别的控制来加以解决,通过不同级别的事务隔离级别,来解决相应的脏读、不可重复读和幻读问题,而事务隔离级别越高,在并发事务场景下会产生的问题就越少,但数据库付出的性能消耗也就越大,并发能力也就越低,因此需要根据不同场景设置不同的事务隔离级别,在事务并发性和数据库性能之间做一个平衡

什么是事务隔离级别?

了解了什么是事务,以及为什么要有事务隔离级别之后,我们再来回答什么是事务隔离级别,就比较轻松了:

在 SQL-92 标准中定义了并发事务场景下脏读、不可重复读和幻读这三种异常情况,而为了解决这些异常情况,SQL-92 标准还定义了 4 种隔离级别来解决这些异常,具体有哪 4 种隔离级别可参照下文

所以简单说,事务隔离级别就是为了解决并发事务场景下脏读、不可重复读和幻读异常而提出的一种应对方式

2. 事务隔离级别有哪些,解决了什么问题?

数据库的事务隔离级别主要有以下 4 种:

  • 读未提交(READ UNCOMMITTED)

    能够读取到其他事务没有提交的数据,不能解决脏读、不可重复读、幻读

  • 读已提交(READ COMMITTED)

    能够读取到其他事务已经提交的数据,可以防止脏读,但不能防止不可重复读和幻读

  • 可重复读(REPEATABLE READ)【MySQL 默认事务隔离级别】

    保证一个事务在相同查询条件下两次查询得到的数据结果是一致的,可以避免不可重复读和脏读,但无法避免幻读

  • 串行化(SERIALIZABLE)

    最高级别的隔离等级,将事务进行串行化,也就是在一个队列中按照顺序执行,可以解决脏读、不可重复读和幻读,但是牺牲了系统的并发性

不同事务隔离级别能解决的异常情况,表格展示如下:

事务隔离级别 脏读 不可重复读 幻读
读未提交(READ UNCOMMITTED) 允许 允许 允许
读已提交(READ COMMITTED) 不允许 允许 允许
可重复读(REPEATABLE READ) 不允许 不允许 允许
串行化(SERIALIZABLE) 不允许 不允许 不允许

3. 事务隔离级别的查看与修改

以 MySQL 引擎为例进行说明

查看 MySQL 引擎事务隔离级别

通过如下 sql 可查看 MySQL 引擎的事务隔离级别:

-- 查询 MySQL 引擎事务隔离级别变量设置,适用于所有版本的 MySQL 引擎查询
SHOW VARIABLES LIKE '%isolation%';

-- 直接查询 MySQL 事务隔离级别变量设置,需明确 MySQL 引擎版本,不同版本的变量设置不一样,可参考下文表格(示例为 5.6 版本)
SELECT @@tx_isolation;

不同版本的 MySQL 引擎(可通过 select version() 查询 MySQL 版本),事务隔离级别变量的设置不一致,以表格形式进行展示:

MySQL 引擎版本 事务隔离级别变量
5.6 tx_isolation
5.7 tx_isolation, transaction_isolation
8.0.19 transaction_isolation

修改MySQL 引擎事务隔离级别

事务隔离级别的参数包含如下 4 种:

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

按照修改生效的作用于区分,可分为如下两种修改:

  • 修改当前会话事务隔离级别(当前会话即为当前连接)

    -- 将当前会话的事务隔离级别设置为可重复读,`REPEATABLE READ` 参数可替换成上述 4 种参数的任意一种
    SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    
  • 修改全局事务隔离级别(即对之后的所有连接均生效)

    -- 将全局事务隔离级别设置为可重复读,`REPEATABLE READ` 参数可替换成上述 4 种参数的任意一种
    SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    

4. 使用 MySQL 客户端模拟脏读、不可重复读、幻读

模拟脏读

可参考 廖雪峰-事务-脏读示例演示,示例简单,清晰明了,包含简短视频演示

模拟不可重复读

可参考 廖雪峰-事务-不可重复读示例演示,示例简单,清晰明了,包含简短视频演示

模拟幻读

可参考 廖雪峰-事务-幻读示例演示,示例简单,清晰明了,包含简短视频演示

你可能感兴趣的:(事务隔离级别)