12【事务的隔离级别】

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 12【事务的隔离级别】,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文


上一篇11【事务处理】

下一篇13【触发器】

目录【MySQL零基础系列教程】



12【事务的隔离级别】

12.1 并发访问的三个问题

并发访问下事务产生的问题:

当同时有多个用户在访问同一张表中的记录,每个用户在访问的时候都是一个单独的事务。

事务在操作时的理想状态是:事务之间不应该相互影响,实际应用的时候会引发下面三种问题。应该尽量避免这些问题的发生。通过数据库本身的功能去避免,设置不同的隔离级别

  • 脏读: 一个事务(用户)读取到了另一个事务没有提交的数据
  • 不可重复读:一个事务多次读取同一条记录,出现读取数据不一致的情况。一般因为另一个事务更新了这条记录而引发的。
  • 幻读:在一次事务中,多次读取到的条数不一致

12.2 设置隔离级别

12.2.1 四种隔离级别:

级别 名字 隔离级别 脏读 不可重复读 幻读 数据库默认隔离级别
1 读未提交 read uncommitted
2 读已提交 read committed Oracle和SQL Server
3 可重复读 repeatable read 是/否 MySQL
4 串行化 serializable

12.2.2 四种隔离级别起的作用:

  • 1)Read uncommitted (读未提交): 简称RU隔离级别,所有事务中的并发访问问题都会发生,可以读取到其他事务没有提交的数据

  • 2)Read committed (读已提交):简称RC隔离级别,会引发不可重复读和幻读的问题,读取的永远是其他事务提交的数据

  • 3)Repeatable read (可重复读):简称RR隔离级别,会引发幻读的问题,一次事务读取到的同一行数据,永远是一样

  • 4)Serializable (串行化): 可以避免所有事务产生的并发访问的问题 效率及其低下

12.3 安全和性能对比

  • 隔离级别越高,安全性就越高,性能越低
  • 隔离级别越第,安全性就越低,性能越高。

12.4 MySQL相关的命令:

查询全局事务隔离级别

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

mysql> 

设置全局事务隔离级别

set global transaction isolation level 四种隔离;		-- 服务器只要不关闭一直有效

修改隔离级别后需要重启会话

12.5 脏读

在并发情况下,一个事务读取到另一个事务没有提交的数据,这个数据称之为脏数据,此次读取也称为脏读。

只有read uncommitted(读未提交)的隔离级别才会引发脏读。

  • 将MySQL的事务隔离级别设置为read committed(读已提交):
mysql> set global transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)

将数据还原:

在这里插入图片描述

12.5.1 脏读演示

session-01 session-02
begin;
begin;
select * from account where name=‘a’;
update account set money=money-200 where name=‘a’;
select * from account where name=‘a’;
rollback;

观察变化:

在这里插入图片描述

12.5.2 解决脏读

将全局的隔离级别进行提升

  1. 打开命令行a,设置全局的隔离级别为read committed:
set global transaction isolation level read committed;

再次执行:

session-01 session-02
begin;
begin;
select * from account where name=‘a’;
update account set money=money-200 where name=‘a’;
select * from account where name=‘a’;
rollback;

观察变化:

在这里插入图片描述

12.6 不可重复读

概念: 在同一个事务中的多次查询应该出现相同的结果,两次读取不能出现不同的结果。

12.6.1 和脏读的区别:

脏读是读取前一事务未提交的脏数据,不可重复读是重复读取了前一事务已提交的数据,但2次读取的结果不同。

应用场景:比如银行程序需要将查询结果分别输出到电脑屏幕和写到文件中,结果在一个事务中针对输出的目的地,两次输出结果却不一致,导致文件和屏幕中的结果不同,银行工作人员就不知道以哪个为准了。

12.6.2 不可重复读演示

1). 将数据进行恢复,并关闭窗口重新登录。

update account set money=1000;
session-01 session-02
begin;
begin;
select * from account where name=‘a’;
update account set money=money-200 where name=‘a’;
commit;
select * from account where name=‘a’;

观察变化:

在这里插入图片描述

两次查询输出的结果不同,到底哪次是对的?

12.6.3 解决不可重复读

1)将数据进行恢复

update account set money=1000;

-- 设置隔离级别为repeatable read
set global transaction isolation level repeatable read;

记得要重启窗口

session-01 session-02
begin;
begin;
select * from account where name=‘a’;
update account set money=money-200 where name=‘a’;
commit;
select * from account where name=‘a’;

观察变化:

在这里插入图片描述

结论:为了保存多次查询数据一致,必须使用repeatable read隔离级别

12.7 幻读

概念:一次事务多次读取到的条数不一致而引发的问题;

在InnoDB(暂时理解是MySQL)中幻读在很多地方都得到了解决,但在一些特殊的情况下,还是会引发幻读问题;

为什么有的情况下能解决,有的情况下解决不了?因为一次事务多次读取到的条数不一致会导致有很多情况发生!

12.7.1 幻读解决情况1):

还原数据:

update account set money=1000;

-- 设置隔离级别为repeatable read
set global transaction isolation level repeatable read;

记得重启客户端

session-01 session-02
begin;
begin;
select * from account;
insert into account values(3,‘c’,1000);
commit;
select * from account;

观察变化:

在这里插入图片描述

幻读问题得到解决

12.7.2 幻读解决情况2):

还原数据

案例:

session-01 session-02
begin;
begin;
select sum(money) from account;
insert into account values(3,‘c’,1000);
commit;
select sum(money) from account;

观察变化:

在这里插入图片描述

12.7.3 幻读问题出现情况1):

还原数据

  • 案例:
session-01 session-02
begin;
begin;
select count(id) from account;
insert into account values(3,‘c’,1000);
commit;
select count(id) from account;
update account set money=0;
select count(id) from account;

观察变化:

在这里插入图片描述

12.7.3 特殊情况:

还原数据

  • 案例:
session-01 session-02
begin;
begin;
select * from account;
select * from account;
insert into account values(3,“c”,1000);
commit;
select * from account;
insert into account values(3,“c”,1000);

观察变化:

在这里插入图片描述

Tips:严格意义来说,上述案例是MySQL的快照机制导致的,不能算幻读;关于幻读我们理解概念就行,即:两次读取到的条数不一致!这就是幻读

12.9 串行化

12.9.1 概念

想要彻底的解决幻读,那么我们必须再把隔离级别调高,数据库的最高隔离级别为串行化(serializable)

串行化相当于锁表操作,即一个事务如果操作了某张表(增加、删除、修改),那么就不允许其他任何事务操作此表,也不允许查询,等第一个事务提交或者回滚之后才可以操作,这样做效率及其低下,因此一般不会采用serializable隔离级别

  • 示例图:
    在这里插入图片描述

12.9.2 串行化演示

1)开启一个银行窗口

-- 还原数据
truncate account;

INSERT INTO account (name, money) VALUES ('a', 1000), ('b', 1000);

set global transaction isolation level serializable; 	-- 设置隔离级别为串行化

2)执行案例:

session-01 session-02
begin;
begin;
update account set money=money-500 where name=‘a’;
select * from account;

在这里插入图片描述

在串行化隔离级别中,相当于锁表的操作,在一个事务对表进行任何的insert/update/delete等操作时,其他事务均不可对其进行操作;在读写上是串行的,并发能力极差;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/131699.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!