【数据库】浅读事务

目录

一、事务的概念

1.1、具体实现:

1.2、事务的特性

二、事务在并发执行中可能遇到的问题

2.1、脏读

2.2、不可重复读

2.3、幻读

三、MySQL的隔离级别


🍉🍉 前言:在介绍 事务 之前,我们先看一个案例:假设 张三同学向李四同学进行转账操作:

  update account set balance = balance - 500 where name = '张三';

  update account set balance = balance + 500 where name = '李四' ;

当系统执行到完成 第一条sql语句 时,网络出现故障,或者数据库挂掉,就会导致:虽然张三同学把钱发了出去,但是李四并没有收到钱的情况。

解决方案:使用 事务 来处理,保证以上两个sql要么全部执行完,要么都不执行(原子性)。

一、事务的概念

🚩 事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。
在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。

1.1、具体实现:

(1) 开启事务: start transaction

(2) 执行多条SQL语句 

(3) 回滚或提交 : rollback / commit         //前者为全部失败,后者为全部成功。  

以上面的转账为例;

start transaction;
-- 张三减少500
update accout set money=money-2000 where name = '张三';
-- 李四增加500
update accout set money=money+2000 where name = '李四';
commit;

1.2、事务的特性

🚩  事务有四个特性,分别为 原子性,一致性,持久性隔离性。其中最核心的是 原子性

1、原子性:这是事务的根本所在,能够把多个SQL打包为一个整体,要么都执行完,要么都不执行,如果执行出错,则 自动回滚(rollback)。

2、一致性:事务执行前后,数据都处在“一致”的状态。(前后的数据能够对的上,eg:张三余额有500rmb,但是想转账给其他人600rmb,这种情况就发生不了)。

3、持久性:事务进行的改动,都是写道硬盘中的,不会随着程序重启/主机重启 而丢失。

4、隔离性:多个事务,并发执行 的过程中,事务之间能够保持 "隔离" ,互不干扰。

二、事务在并发执行中可能遇到的问题

🚩🚩  前言:我们知道,MySQL 的本体是一个服务器,执行SQL语句,本质上也是客户端把SQL发给服务器,然后服务器再去执行。

所以,事务也是同样的,如果在同一时刻,多个客户端都给服务器发送了事务,让其执行,如果操作的是 不同 的 数据库/表,就不会有事,

但是如果操作 一个 数据库/表,可能就会存在问题。(这也就是 隔离性 的意义所在,将问题稳定在可控范围之内)。

2.1、脏读

脏读 就是一个事务读到另一个事务没有提交的数据。事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,事务B读到的就是脏数据。

事例:小白同学要给他舍友发红包,在发的时候,手机上输入了50,但是其实是自己手快按错了(事务还未提交),但是这个时候舍友不小心看到了,以为要给自己发50,还在暗暗高兴,但是小白这个时候把数据改为20(回滚),并发送给了舍友。舍友看到后傻眼了,本来不是50吗???

分析:舍友以为小白要发50,实际其实是准备发20,舍友看到的是小白未发送出去的数据,这就是脏读,也就是读取脏的数据。

解决方案:在事务A修改数据的时候,不允许事务B读取数据,当A完成后,再让事务B读取,相对于是对写操作,加锁。

在写加锁之前,事务A修改操作于事务B的读取操作都是完全并发的(此时并发性最高,隔离性最低),当写加锁之后,事务A在修改数据时候事务B就不能读取,并发性降低(效率降低),隔离性提高了(准确性)。

2.2、不可重复读

不可重复读 就是一个事务读到另一个事务修改后并提交的数据(update)。在同一个事务中,对于同一组数据读取到的结果不一致。比如,事务B 在 事务A 提交前读到的结果,和在 事务A 提交后读到的结果可能不同。不可重复读出现的原因就是由于事务并发修改记录而导致的。

事例:小林同学在买皮肤前的查看账户中有2000点卷,在他准备买时候(开启事务),肚子疼了,放下手机去了厕所,这时小林同学的女朋友上线帮其买了其他的东西,这是小林同学发现皮肤买不了(被修改数据了),点卷被消耗了。

分析:在这个事例中,涉及到了两个事务(小林同学与女朋友的),当小林事务开启时(查看有2000点卷准备买的时候),此时女朋友这个事务就将点卷进行了消费,即对数据进行了修改,导致商城系统两次读取到的数据不一样。出现了一个事务范围内两个相同的查询却返回不同的数据,这就是不可重复读,这是由于数据更新导致的,不能重复读取相同的数据。

解决方案:在事务B读取数据的时候,另一方也不去修改这个数据,也就是 读加锁 操作。

随着引入读加锁的操作,并发程度又降低了(效率降低),隔离性又提高了(数据准确性也提高了)。

2.3、幻读

此问题为不可重复读的特殊情况。

幻读 就是一个事务读到另一个事务新增加并提交的数据。在同一个事务中,对于同一组数据读取到的结果不一致。比如,事务A 新增了一条记录,事务B 在 事务A 提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读出现的原因就是由于事务并发新增记录而导致的。

事例:小林同学在考场中偷偷瞄隔壁小白同学的一道选择题的答案,先看到了这道题选B,这时小白同学发现这道题还有一个解,于是添加上了一个C选项,后面小林又瞄到小白同学这道题的答案(关心的数据),发现写的是B,C两个选项(结果集发生了变化)。似乎出现了幻觉,这就是幻读。

分析:在这个事例中,事务B读取了数据,接着另一个事务A插入了一条数据。在随后的查询中,事务B就会发现多了一条原本不存在的记录,就好像发生了幻觉一样,这是由于数据新增导致的。

解决方案:实现 串行化 

此时 并发程度最低(串行执行),效率最低 ,但是隔离性最高,数据准确度也就最高。

🚩小结:

上述脏读,不可重复读,幻读,都是并发执行事务中,可能带来的影响,但是这并非都是bug(看具体需求)。

如果需求对于数据要求精度不高,上述问题就不是bug,这是可以让并发程度高,隔离性低,提高效率。

如果需求对于数据要求精度高,上述问题可能就是bug,这是可以让并发程度低,隔离性高,提高准确程度。

三、MySQL的隔离级别

🚩 根据不用的需求场景,MySQL提供了 "隔离级别" 选项,分为4个挡位,分别是:分别是:读未提交、读已提交、可重复读、序列化。

1、read uncommitted(读未提交)  允许读未提交的数据,并发程度最高,隔离性最低,可能存在 脏读/不可重复读/幻读

2、read committed(读已提交): 只能读提交之后的数据,相当于写加锁,并发程度降低,隔离性提高,解决了脏读,可能存在 不可重复读/幻读 的问题。

3、repeatable read(可重复读): [默认] 相当于读和写都加锁了,并发程度再降低,隔离性再提高,解决了 脏读/不可读问题,可能存在幻读。

4、serializable(序列化): 严格执行串行化,并发程度降低,隔离性最高,解决了 脏读/不可重复读/幻读的问题,效率最低

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值