Mysql8.0.12的四种事务隔离级别

使用测试环境: MacOS Mojave 10.14.2 + mysql8.0.12+InnoDB(默认搜索引擎)

Mysql8.0.12的四种事务隔离级别_第1张图片

事务的基本要素(ACID)

  • 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  • 一致性(Consistency):事务开始前和结束后,数据的完整性约束没有被破环。比如A向B转了钱,转账前后钱的总数不变。
  • 隔离性(Isolation):多个用户并发访问数据数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间的数据相互隔离。比如事务A和事务B都修改同一条记录,这条记录就会被重复修改或者后者会覆盖前者的修改记录。
  • 持久性(Durability):事务完成后,事务对数据库的更新被保存到数据库,其结果是永久的。

 

MySQL8事务隔离级别

mysql8的可重复读(repeatable-read中不会出现幻读的情况)

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

事务的并发问题

  1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

  2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读               取同一数据时,结果 不一致。

  3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

  小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

查询当前的mysql8的默认隔离级别为第三级别可重复读(repeatable-read) 

show variables like 'transaction_isolation';

Mysql8.0.12的四种事务隔离级别_第2张图片

一、隔离级别第一级别: 读未提交(read-uncommitted)

(1)打开客户端A

先将事务的隔离级别设定为读未提交 set session transaction isolation level read uncommitted;

并开启事务  start transaction;

Mysql8.0.12的四种事务隔离级别_第3张图片

Mysql8.0.12的四种事务隔离级别_第4张图片

(2)在A客户端事务提交之前,打开另一个客户端B,更新表account,将id为1的balance-50

Mysql8.0.12的四种事务隔离级别_第5张图片

(3)此时虽然客户端B的事务还没有提交,但是客户端A就可以查询到B已经更新的数据:

Mysql8.0.12的四种事务隔离级别_第6张图片

 (4)此时一旦客户端B的事务因为某种原因回滚rollback,所有的操作都将会被撤销,那么客户端A查询到的数据其实就是脏数据:

Mysql8.0.12的四种事务隔离级别_第7张图片

(5)客户端A执行更新语句update account set balance =balance -50 where id =1; 此时id为1的balance没有变成0,而是还是50,因为事务B中发生了回滚,A中之前读取到的50就是脏数据,真实的数据还是100.

Mysql8.0.12的四种事务隔离级别_第8张图片

二、读已提交(第二级别 read-committed)

       解决了脏读问题,但是出现了不可重复读问题,存在幻读问题

(1)打开客户端A设置当前的事务隔离级别为read committed (未提交读)查询表account的所有记录:

Mysql8.0.12的四种事务隔离级别_第9张图片

(2) 将客户端B的事务的隔离级别调整为read committed级别,并开启事务,开始更新表account

(3) 此时,客户端B的事务还没有提交,客户端A是不能查询到B已经更新的数据,解决了 脏数据的问题

(4)客户端B提交事务

(5) 客户端A执行上一次相同的查询,结果就回发现与上一次查询结果不同,就产生了不可重复读的问题

Mysql8.0.12的四种事务隔离级别_第10张图片

三、可重复读(repeatable read) (MySQL事务的默认隔离界别)

(1)首先打开客户端A将事务的隔离级别调整为repeatable read 级别

Mysql8.0.12的四种事务隔离级别_第11张图片

(2) 打开客户端B将事务的隔离级别调整为repeatable read级别,并对表account进行更新,提交

(3)在客户端A查询表account的所有记录就回发现,无论客户端B是否提交查询的数据结果都是一致,没有出现不可重复读的问题

(4)在客户端A,接着执行update account set balance =balance -50 where id =1;balance 没有变为100-50=50

id =1 的balance变成了0,数据的一致性得到保证。可重复读的隔离级别下是用来 MVCC机制,select 操作不会更新版本号

是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。

  (5)同时发现了一个问题MySQL8已经不出现幻读的情况了,打开客户端B,尝试插入一条新数据发现根本就不会提交

Mysql8.0.12的四种事务隔离级别_第12张图片

4、串行化

(1)在客户端A中设置当前事务模式为Serializable

Mysql8.0.12的四种事务隔离级别_第13张图片

(2)打开客户端B,并设置当前事务模式为serializable,插入一条记录报错,mysql中事务隔离级别为serializable时会锁表,

客户端A就不可能对account表进行任何操作,同理反过来,A中如果先查询,会发生锁表现象,B表中的任何操作也会被拒绝

 发生锁表,因此不可能出现脏读数据、不可重复读、出现幻读的情况,这种隔离级别并发性比较低,开发中很少使用。

Mysql8.0.12的四种事务隔离级别_第14张图片

Serializable完全串行化的读,每次读都需要获得表级共享锁,读写相互会相互互斥,这样可以更好的解决数据一致性的问题,但是同样会大大的降低数据库的实际吞吐性能。所以该隔离级别因为损耗太大,一般很少在开发中使用。

补充:

1、事务隔离级别为读提交(read committed  不可重复读,第二级别)时,写数据只会锁住相应的行

2、事务隔离级别为可重复读时(repeatable read ,第三级别),如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有 索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。

3、事务隔离级别为串行化时(serializable ,第四级别),读写数据都会锁住整张表

4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

你可能感兴趣的:(MySQL)