【MySQL】MySQL事务(二)

        前言:上节内容我们主要介绍了ACID四个特性和rollback、commit、自动提交和非自动提交。 这节将看一下事物的特性——隔离性。下面友友们开始学习吧。

        ps:本节内容建议友友们看过上一节再观看哦。

目录

事务的隔离性

如何理解隔离性

隔离级别

 隔离试验示例

如何查, 设置mysql的隔离界别

读未提交

​编辑

读提交 

 可重复读

串行化


事务的隔离性

        要理解隔离性, 我们就要知道什么叫做隔离性, 什么叫做隔离级别, 为什么会有这么多隔离级别。

如何理解隔离性

        首先我们要知道, mysql在启动后, 会被多个客户端并发的访问。每一个客户端都可以向mysql发送事务, 对于我们上层来说,这些事务一定有执行前, 执行中, 执行后。一旦执行中出现问题, 就会发生回滚。所以单个事务,对用户表现出来的特性, 就是原子性。

        但是, 多个事务执行的时候, 可能会互相影响。比如同时访问一张表, 同时修改一张表。所以, 在数据库当中,为了保证事务之间尽量互不干扰,就有了一个重要的特性——隔离性。

        数据库中,允许事务收到不同程度的干扰, 这个就叫做隔离级别。

        如果两个人都在同时访问数据库。 这两个人都开启了事务。 但是一个人想要update, 一个人想要select。 那么请问是update先执行呢, 还是select先执行呢? 

        这里并不是谁先执行的问题——就比如一个小孩出生, 假如这个小孩是00后。 他的父母是70后, 80后。 那么这个小孩不需要关注他的父母从出生到生下他这段时间里面他的父母做过什么。 也比如一个革命战士, 就比如一百年前, 几十年前的革命战士。 他们在他们的那个年代努力奋斗。但是他们看不到如今的中国是什么样子。 ——每一个人, 都只是需要看到自己从出生到死亡的这一段时间内的事情。 其他时间段的时间, 这些人不需要关心。  而这些, 其实就是隔离性。 就是说我们不用获取信息总是获取最新的, 也不能获取信息总是获取最旧的。 我们只需要获取自己这个时间段内的就行。 

        所以, 对于update和select谁先执行, 应该是取决于两个谁先来的, 谁先来的谁就先执行。对于事务来说, 谁先到来, 谁就先执行。但是对于先到来的事务不一定先退出。可能先到的执行的很慢, 后到来的执行的很快。那么后到来的先执行完, 先到来的后执行完。而且可能在我们到来的期间, 另一个事务把数据更新了。 然后我们此时select也应该按照隔离级别确定应不应该看到最新的数据。

隔离级别

  • 读未提交:事务1所做的任何修改, 不需提交事务2也能立即看到。
  • 读提交:事务1所做的任何修改, 只有当提交后事务2才能立即看到。
  • 可重复读:事务1无论做任何修改以及提交。 只有当事务2也结束后,再启事务才能看到。隔离级别较高, 也是mysql默认的隔离级别。
  • 串行化:最高的隔离界别所有的CURD操作, 必须按照到来的顺序一个一个执行, 一个执行完才能下一个。

 隔离试验示例

如何查, 设置mysql的隔离界别

        要查看隔离界别, 首先我们要知道什么是会话隔离界别, 什么是全局隔离级别。 会话隔离界别就是只影响这一次登录。 而全局隔离级别也影响后续的登录。

select @@global.transaction_isolation;--查看全局隔级别

select @@transaction_isolation; --查看会话(当前)全局隔级别

select @@session.transaction_isolation; --查看会话隔离界别

然后设置隔离界别

set [session | global] transaction isolation level {read uncommitted | read committed | repeatable read | serializable}

上面的方括号里面的session和global二选一, 设置系统还是会话。 然后花括号里面的四个选择一个。 读未提交, 读提交, 可重复读, 串行化。

现在试验一下串行化

        设置当前会话串行化:

set session transaction isolation level serializable;

但是新起会话不收到影响:

 再设置回来:

set session transaction isolation level read uncommitted;

如果全局隔离级别和会话隔离级别不同, 就会默认使用会话隔离级别。

读未提交

        我们现在来读未提交。

先启动两个事务:

然后右边查看一下表中的数据:

然后在左边插入数据张三:

之后再从右边查看, 就能看到数据已经查看到了。

我们左边还没提交呢, 右边就能看到。 这就叫什么, 这就叫做读未提交!一个事务在执行中,读到另一个事务的更新但是还没有commit的数据, 这种情况叫做脏读。——这是一种不合理的现象。

rollback回滚也能看到数据又恢复了:

读提交 

先将事务的隔离级别改为读提交:

 两边启动事务:

先查看一下表中的数据:

然后我们插入数据张三:

然后右边查一下数据, 会发现看不到表数据的更新:

但是我们左边查的话就能看到:

 然后我们左边提交commit:

右边再查, 就会看到数据修改了:

        这种一旦提交就能看到的就叫做读提交。 读提交好像解决了脏读的问题。 但是又出现了另一个问题:就是我们左边在提交前和提交后, 我们右边select查到的数据结果是不一样的。 也就是说我们右边一直select, 结果某一次select的时候, 数据突然变了。 ——这种现象, 就叫做不可重复读。

        那么, 不可重复读是问题吗?

        ——首先, 我们提交了,就让另一个人看到, 不应该吗? 其实是应该的。 但是不应该让另一个人在运行期间看到, 应该是让另一个人结束后, 再起事务的时候看到。  

        就比如我们的一个表, 有员工ID, 有员工名字, 有员工薪资。如果路人A想要涨工资, 就和老板去谈。 谈妥了, 老板就告诉路人B修改一下数据库中的路人A的薪资。 这个时候呢, 路人C正在查数据库中的人们的薪资, 根据薪资来归类。 所以呢,这个时候路人C通过筛选, 先查工资(1000-2000)的人,里面有路人A。 然后呢, 路人B就对路人A的薪资进行修改, 修改成了2500。 然后路人C查的有点慢, 他敲了半天, 终于查出了(2000-3000)的工资的人。 然后一看, 里面也有路人A。 那么这就出现了问题, 这个路人A出现了两次。 那么这个路人C对于路人A到底该怎么分类, 就出现问题了。

        所以, 不可重复读有问题吗? 答案是有问题。

 可重复读

先设置可重复读:

启动我们的事务:

然后查看我们的数据:

然后我们进行插入,之后右边查看, 会发现, 右边没有数据更新:

然后我们左边直接提交了, 右边也看不见:

这种即便commit, 其他事务也看不到, 就叫做可重复读。 

然后重启事务, 就能看到了:

        对于可重复读, 有的数据库因为insert的插入有些特殊, insert不能可重复读。所以就形成了幻读现象, 也就是好像出现了幻觉一样。 mysql是解决了这个问题的。

串行化

 设置隔离级别:

        MySQL的串行化并不是传统意义上的事务一先执行, 此时事务二的任何操作都会被阻塞住, 只有当事务一commit之后事务二在执行。 MySQL的串行化利用的是两种锁, 一种是select共享锁, 一种是insert或者delete排他锁。 这两种锁覆盖的是行, 就比如insert插入数据, 就要获取对应行的排他锁, select查询数据, 就要获取查询到的所有行的共享锁。

        这种情况下就非常容易发生死锁。 因为如果双方都有了共享锁, 共享锁兼容共享锁而排斥排他锁,双方就容易都进行了select语句, 都获得了整张表的共享锁, 然后双方再insert语句, 就会发生一种情况: 双方都有共享锁, 第一个insert的想要获取对方的共享锁, 被阻塞住,第二个insert也想获得对方的共享锁, 被阻塞住,形成死锁。 所以, 避免使用select语句在串行化的事务种。 

        通过上面的例子我们就能看出来, 隔离级别越严苛,安全性就越高。 但是数据库的并发度就越低。所以就要在其中找到一个平衡点。根据实际需求, 用户就可以使用不同的隔离方案。决定在用户, 不在于数据库, 所以mysql提供了四种隔离级别!!!

 ——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!!   

评论 169
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值