MySQL 事务特性四种隔离级别 (图示每一步的操作)和产生的问题

Posted 猎人在吃肉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL 事务特性四种隔离级别 (图示每一步的操作)和产生的问题相关的知识,希望对你有一定的参考价值。

文章目录

本文实验的测试环境:Windows 10+cmd+mysql5.6.36+InnoDB

一、事务的特性(ACID)

  1. 原子性(Atomicity):
    事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。
    事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。
    也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。

  2. 一致性(Consistency):
    事务开始前和结束后,数据库的完整性约束没有被破坏 。
    比如A向B转账,不可能A扣了钱,B却没收到。

  3. 隔离性(Isolation):
    一个事务的执行,不能被其他的事务干扰。(如果 隔离级别 的过低时,会受影响的)
    比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

  4. 持久性(Durability):
    一个事务一旦提交,它对数据的影响的永久的,接下来的其他操作和数据库故障不会对其有任何的影响。

二、MySQL事务的隔离级别和产生的问题

2.1、隔离级别

隔离级别描述
读未提交( read-uncommitted一个事务可以读取另一个事务未提交的变更(数据)。
读已提交( read-committed只允许事务读取已经被其他事务提交的变更(数据)。
可以避免脏读,但不可重复读,幻读依然可能出现
可重复读( repeatable-read确保事务可以多次从一个字段中读取相同的值,
在这个事务持续期间,禁止其他事务对这个字段进行更新。
可以避免脏读、不可重复读,但是幻读的问题依然存在。
串行化 ( serializable-

2.1.1、查看隔离级别

select @@tx_isolation;

select @@global.tx_isolation;

mysql 默认的事务隔离级别为 repeatable-read

oracle 默认的事务隔离级别为 read-committed

2.1.2、设置隔离级别

set transaction isolation level repeatable read;

set global transaction isolation level repeatable read;

隔离级别设置的参数:

  • read uncommitted (读未提交)
  • read committed (读已提交)
  • repeatable read (可重复读)
  • serializable (串行化)

2.2、隔离级别产生的脏读不可重复读幻读 的问题

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

2.2.1、脏读:

事务A读取了事务B未提交的更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。

2.2.2、不可重复读:

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

2.2.3、幻读:

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

2.3、不可重复读的 和 幻读 的区别

不可重复读 侧重于 修改,

幻读 侧重于 新增 或 删除。

2.3.1、解决方法:

不可重复读 的解决方法 是 锁住满足条件的行

幻读 的解决方法是 锁表

三、举例说明不同的隔离级别和产生的问题(图)

创建表:

CREATE TABLE `account` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(20) DEFAULT NULL,
    `balance` decimal(10,0) DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

插入数据:

insert into `account` (`id`, `name`, `balance`) values('1','lilei','450');
insert into `account` (`id`, `name`, `balance`) values('2','hanmei','16000');
insert into `account` (`id`, `name`, `balance`) values('3','lucy','2400');

3.1、读未提交(出现脏读):

(1)打开一个客户端A,并设置当前事务模式为 read uncommitted(读未提交),查询表 account 的初始值。

(2)在客户端A的事务提交之前,打开另一个客户端B,更新表 account 。

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

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

(5)在客户端A执行更新语句 update account set balance = balance - 50 where id =1
lilei 的balance没有变成350,居然是400,是不是很奇怪,数据不一致。
如果你这么想就太天真 了,在应用程序中,我们会用 400-50=350 ,并不知道其他会话回滚了,要想解决这个问题可以采用读已提交的隔离级别。

3.2、读已提交(出现不可重复读)

(1)打开一个客户端A,并设置当前事务模式为 read committed(未提交读),查询表account的所有记录。

(2)在客户端A的事务提交之前,打开另一个 客户端B,更新表 account

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

(4)客户端B的事务提交。

(5)客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题。

3.3、可重复读(出现幻读)

(1)打开客户端A,并设置当前事务模式为 repeatable read ,查询表 account 的所有记录。

(2)在客户端A的事务提交之前,打开 客户端B,设置事务模式为 repeatable read,开启事务,更新表 account ,并提交。

(3)在客户端A查询表 account 的所有记录,与 第1步 查询结果一致,没有出现不可重复读的问题。

(4)在客户端A,接着执行 update account set balance = balance - 50 where id = 1
balance 值不是 450-50=400,balance 值用的是 第2步 中的400来算的,减去50,结果是350,数据的一致性没有被破坏。
可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。

(5)重新打开客户端B,开启事务,插入一条新数据,并提交。

(6)客户端A,查询表account,没有查出 新增数据 ,提交事务后,又查询, 查询出新增的数据,这就是 幻读

4.4、串行化

(1)打开客户端A,设置当前事务模式为 serializable,开启事务,查询表 account 的数据。

(2)打开客户端B,并设置当前事务模式为serializable,开启事务,插入一条数据,等待一段时间后报错。
因为表被锁,造成插入失败。
mysq l中事务隔离级别为 serializable 时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。

四、知识扩展:

1、事务隔离级别为读提交时,写数据只会锁住相应的行

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

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

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

5、MYSQL MVCC实现机制参考链接:https://blog.csdn.net/whoamiyang/article/details/51901888

6、关于next-key 锁可以参考链接:https://blog.csdn.net/bigtree_3721/article/details/73731377

五、参考文章:

MySQL的四种事务隔离级别

MySQL事务(脏读、不可重复读、幻读)

以上是关于MySQL 事务特性四种隔离级别 (图示每一步的操作)和产生的问题的主要内容,如果未能解决你的问题,请参考以下文章

Mysql事务的四种特性和隔离级别

mysql基础---事务 事务的四大特性(ACID) 四种隔离级别

Mysql的事务特性,四种隔离级别及原理

Mysql的事务特性,四种隔离级别及原理

Mysql的事务特性,四种隔离级别及原理

mysql 四种隔离级别