【MySQL】——事务的隔离性

发布于:2025-04-13 ⋅ 阅读:(21) ⋅ 点赞:(0)

目录

一、前言

二、隔离级别

1、查看与设置隔离性

2、读未提交 【Read Uncommitted】

3、读提交【Read Committed】

4、 可重复读【Repeatable Read】

5、串行化 【Serializable】

三、总结


一、前言

在上篇事务一文中,我们提到了事务的四个属性 原子性、持久性、隔离性、一致性。原子性和持久性我们已经在上篇文章中见识到了,但是隔离性和一致性又该怎么理解呢?

我们首先来看事务的隔离性,数据库中为了保证事务执行过程中尽量不受干扰,就有了一个重要的特征:隔离性

同时,数据库中允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

二、隔离级别

首先我们先了解一下MySQL数据库中定义了四种标准的隔离级别:

  1. 读未提交【Read Uncommitted】: 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复读等,我们上篇文章为了做实验方便观察现象,用的就是这个隔离性。
  2. 读提交【Read Committed】 :该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果。
  3. 可重复读【Repeatable Read】: 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题。
  4. 串行化【Serializable】: 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用)

隔离级别如何实现:隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。常见有,表锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等。不过,我们先了解就行。

1、查看与设置隔离性

设置当前会话 or 全局隔离级别语法

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ
COMMITTED | REPEATABLE READ | SERIALIZABLE}

如我们所想,设置当前会话隔离性,另起一个会话并不会影响新会话的隔离性。若设置全局隔离性,当另起一个新会话时,该会话的隔离性会被影响。

2、读未提交 【Read Uncommitted】

此时客户端A B都在事务中,都没有提交,可以看到在客户端隔离性为读未提交的状态下,客户端A在一个事务中对表中数据更新但是还没提交的情况下,客户端B在事务中也会看到表的更新。 

上面的现象就称为脏读即一个事务在执行中,读到另一个执行中事务的更新(或其他操作),但是未commit的数据。

该隔离性几乎没有枷锁,虽然效率高,但是问题太多了,所以严重不建议采纳。

3、读提交【Read Committed】

 可以看到客户端B是在客户端A的事务提交之后才在它的事务中看到客户端A对表的修改的,而在客户端A没有提交的情况下,客户端B是看不到的,无论自己是否提交。

所以这就造成了在同一个事务内(客户端B事务),同样的读取,在不同的时间段(是在整个事务还在运行的时间段)读取到了不同的值,这种现象就称为 不可重复读

4、 可重复读【Repeatable Read】

可以看到只有在客户端AB同时提交事务之后,客户端B才能看到客户端A在事务中对于表中数据的更新。也就是说客户端B在自己的事务中无论读多少次,读到的內容都是一样的,这也就是为什么该隔离性被称为 可重复读

这里如果将客户端A对表的更新操作变为插入操作,那么在客户端B的事务中还会有可重复读的情况吗?

我们要知道一般的数据库在可重复读的情况的时候,无法屏蔽其他事务insert的数据,因为隔离性实现是对数据加锁完成的,而insert待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题。会造成虽然大部分内容是可重复读的,但是insert的数据在可重复读情况被读取出来,导致多次查找时,会多查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读(phantom read)

但是MySQL在可重复读的情况下并没有出现幻读的问题,解决的方式是用Next-Key锁(GAP+行锁),这里稍作了解。

5、串行化 【Serializable】

此时客户端AB都在事务中,可以看到双方读取內容很正常,不会串行化,但是客户端A更新内容时, 会卡顿

当我们提交客户端B的事务后,客户端A的更新就可以继续,只不过由于事务等待的时间超过了MySQL的锁等待超时限制,所以出现了报错。

在RR隔离性下,除了update操作, insertdelete之间是会有加锁现象的,但是select和这些操作是不冲突的,这就是通过读写锁+MVCC完成的隔离性。

RR对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用

三、总结

  • 其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个衡点。
  • 不可重复读的重点是修改和删除:同样的条件, 你读取过的数据,再次读取出来发现值不一样了幻读的重点在于新增:同样的条件, 第1次和第2次读出来的记录数不一样
  • 说明: mysql 默认的隔离级别是可重复读,一般情况下不要修改
  • 上面的例子可以看出,事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大

接下来谈谈一致性

  • 成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一致)的状态。因此一致性是通过原子性来保证的。
  • 其实一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是,一致性,是由用户决定的。
  • 事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务

感谢阅读!


网站公告

今日签到

点亮在社区的每一天
去签到