美文网首页
浅谈事务隔离级别

浅谈事务隔离级别

作者: AD刘涛 | 来源:发表于2020-03-31 23:25 被阅读0次
思考?
  1. 事务并发处理可能存在的三种异常有哪些?什么是脏读、不可重复读和幻读?
  2. 针对可能存在的异常情况,四种事务隔离的级别分别是什么?
  3. 如何使用 MySQL 客户端来模拟脏读、不可重复读和幻读?

四种隔离级别

这四种隔离级别从低到高分别是:

  • 读未提交(READ UNCOMMITTED )
  • 读已提交(READ COMMITTED)
  • 可重复读(REPEATABLE READ)
  • 可串行化(SERIALIZABLE)

这些隔离级别能解决的异常情况如下表所示:

隔离级别 脏读 不可重复读 幻读
读未提交 允许 允许 允许
读已提交 禁止 允许 允许
可重复读 禁止 禁止 允许
可串行化 禁止 禁止 禁止

事务并发处理可能存在的三种异常有哪些?

在了解数据库隔离级别之前,我们需要了解设定事务的隔离级别都要解决哪些可能存在的问题,也就是事务并发处理时会存在哪些异常情况

这些异常情况级别分别为:

  • 脏读(Dirty Read)
  • 不可重复读(Nnrepeatable Read)
  • 幻读(Phantom Read)

如何理解脏读?

下面我们通过案例进行演示:

  1. 首先我们通过以下命令先来查看下当前会话的隔离级别
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)

然后你能看到当前的隔离级别REPEATABLE-READ,也就是可重复读

  1. 我们修改当前事务隔离级别,将其改为READ UNCOMMITTED:

在mysql客户端输入以下指令:

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
  1. 查看当前事务隔离级别:
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+------------------+
| Variable_name         | Value            |
+-----------------------+------------------+
| transaction_isolation | READ-UNCOMMITTED |
+-----------------------+------------------+
1 row in set (0.00 sec)
  1. 关闭自动提交并查看是否已更改(MySQL 默认是事务自动提交,这里我们还需要将 autocommit 参数设置为 0,命令如下:)
mysql> SET autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
1 row in set (0.01 sec)

接着我们以同样的操作启动客户端 2,也就是将隔离级别设置为 READ UNCOMMITTED(读未提交)autocommit 设置为 0

模拟脏读:

  1. 我们先在客户端1开启一个事务,在heros_temp表中写入新增的英雄"赵子龙",注意这个时候不要提交
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `heros_temp` VALUES (4, '赵子龙');
Query OK, 1 row affected (0.00 sec)

我们此时查看客户端2,你会发现此时表中已经存在了此条记录:

mysql> select * from heros_temp;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 张飞      |
|  2 | 关羽      |
|  3 | 刘备      |
|  4 | 赵子龙    |
+----+-----------+
4 rows in set (0.00 sec)

注意我们目前还没有提交,你能发现客户端2中读取了客户端1未提交的新英雄“赵子龙”,实际上客户端 1 可能马上回滚,从而造成了脏读。所以,所谓脏读就是,一个事务读取了另一个事务改写但还未提交的数据。

模拟不可重复读:

  1. 我们用客户端 1 来查看 id=1 的英雄:
mysql> select name from heros_temp where id = 1;
+--------+
| name   |
+--------+
| 张飞   |
+--------+
1 row in set (0.00 sec)
  1. 此时我们在客户端 2 对 id=1 的英雄进行修改:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update heros_temp set name="张翼德" where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

  1. 我们在客户端 1 在进行查看同一条记录:
mysql> select name from heros_temp where id = 1;
+-----------+
| name      |
+-----------+
| 张翼德    |
+-----------+
1 row in set (0.01 sec)

你会发现此时,在同一个事务中同一条查询语句出现的结果竟然不一样。这样的一种行为,我们称作不可重复读

模拟幻读

  1. 在了解幻读之前,我们先恢复当前事务隔离级别为Repeatable Read

  2. 然后我们打开两个mysql客户端:

我们现在分别在客户端1,2开启事务:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
  1. 我们在客户端2搜索一条不存在的记录,比如:
select * from heros_temp where id = 3000;

结果如下:


mysql> select * from heros_temp where id = 3000;
Empty set (0.00 sec)

  1. 此时我们在客户端1插入该条记录:

mysql> INSERT INTO `heros_temp` VALUES (3000, '刘备');
Query OK, 1 row affected (0.00 sec)
  1. 然后我们在去客户端2查询,结果如下:
mysql>  select * from heros_temp where id = 3000;
Empty set (0.00 sec)
  1. 我们此时提交客户端1的数据:
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
  1. 然后我们再次去客户端2查询,结果如下:
mysql>  select * from heros_temp where id = 3000;
Empty set (0.00 sec)

客户端1的数据已经提交,但我们在客户端2依旧无法查到。

  1. 见证奇迹的时候到了:我们在客户端2进行数据更新
mysql> update heros_temp set name = '曹植' where id = 3000;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

是不是很惊讶!!我们刚刚在客户端2查询id=3000的记录时,数据显示为Empty set,但我们却更新成功了。

  1. 此时我们再次查询,结果出来了。
mysql>  select * from heros_temp where id = 3000;
+------+-----------+
| id   | name      |
+------+-----------+
| 3000 |  曹植      |
+------+-----------+
1 row in set (0.00 sec)

以上就是幻读,所以幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。

不可重复读 VS 幻读的区别:

不可重复读是同一条记录的内容被修改了,重点在于UPDATEDELETE

幻读是查询某一个范围的数据行变多了或者少了,重点在于INSERT.

所以,SELECT显示不存在,但是INSERT的时候发现已存在,说明符合条件的数据行发生了变化,也就是幻读的情况,而不可重复读指的是同一条记录的内容被修改了。

不可重复读是对于同一条记录内容不可重复读幻读是对于某一范围的数据集,发现查询数据集的行数多了或者少了,从而出现的不一致。所以不可重复读的原因是 对于要查询的那条数据进行了UPDATEDELETE,而幻读是对于要查询的 那个范围的数据集,进行了INSERT

总结:
读未提交:在这个隔离级别下,事务A会读到事务B未提交的数据,在事务B回滚后,事务A读到的数据无意义,是脏数据,称为 脏读

读已提交:在这个隔离级别下,只有在事务B已提交时,事务A才能读到,如果事务A先查询id为1的记录,之后事务B修改这条记录并提交事务A再读取两次结果会不一致,所以不可重复读

可重复读:在这个隔离级别下,就算事务B的修改已经提交,事务A读到的数据依旧是一致的。当事务B插入一条新数据并提交之后,事务A查询不到当前数据,查询不到就以为不存在,但是事务A却可以更新这条数据成功,并且更新后再次查询,数据出现了。一开始查询不到,但能修改,再次查询又出现了,跟幻觉一样,所以称为幻读

幻读

相关文章

  • Spring 中的事务隔离级别

    什么是事务隔离级别? 事务隔离级别是对事务 4 大特性中隔离性的具体体现,使用事务隔离级别可以控制并发事务在同时执...

  • 浅谈事务隔离级别

    思考? 事务并发处理可能存在的三种异常有哪些?什么是脏读、不可重复读和幻读? 针对可能存在的异常情况,四种事务隔离...

  • MySQL_tx_isolation

    事务隔离级别 一、数据库事务隔离级别数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、...

  • MySQL事务隔离级别和实现原理,看这一篇就够了!!!

    经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗,事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么...

  • 面试题

    基础知识 1、事务隔离级别 补充: 1、事务隔离级别为读提交时,写数据只会锁住相应的行 2、事务隔离级别为可重复读...

  • 数据库事务相关

    事务隔离级别(tx_isolation)mysql 有四级事务隔离级别 每个级别都有字符或数字编号 级别symbo...

  • 关于Spring的事务Transactional,锁同步,并发线

    Spring事务传播机制和数据库隔离级别 在标准SQL规范中定义了4个事务隔离级别,不同隔离级别对事务处理不同 。...

  • Mysql事务

    事务隔离级别 事务隔离级别有四种:read-uncomitted,read-commited,repeatable...

  • mysql事务-2020-11-21

    use test查询事务隔离级别:select @@tx_isolation; 设置事务隔离级别://全局的set...

  • MYSQL事务

    常用语句 MYSQL事务,锁表 事务控制语句 事务的隔离级别 隔离级别描述产生风险READUNCOMMITTED ...

网友评论

      本文标题:浅谈事务隔离级别

      本文链接:https://www.haomeiwen.com/subject/yvsnuhtx.html