mysql 默认事务隔离级别_MySQL事务隔离级别

23d39e2baf3259954797d3460155df1d.png

对于数据库的隔离级别之前一直没有做详细整理,最近项目运行中发现了一个问题,所以抽时间对这块认真研究了下

业务场景:
服务A在处理流程中,会调用外部服务B,然后写入一条数据,服务B执行完成后,会回调服务C的接口更新服务A写入的数据。问题:
在服务B回调服务C的时候总是找不到服务A写入的数据,在服务C中添加延时重试,问题依然存在,但此时查看数据库,对应的数据是已经存在。

先说原因吧,是因为MySQL的事务默认隔离级别是:可重复读。
在服务A调用服务B后,还没有写入数据到数据库,服务B就已经回调服务C了,服务C此时肯定是找不到对应的数据的,由于MySQL默认隔离级别是可重复读(即在一个事务中,对于同一份数据读取都是一样的),所以即使服务A已经写入了数据,服务C依然读取不到。

解决方案:
在服务C中的查询,不要放到一个事务里面,单独提取一个方法,后面的更新逻辑放到同一个事务中

什么是事务?

数据库事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
比如:某人在商店购买100商品,其中包括两个操作:
1.该人账户减少100元
2.商店账户增加100元
这两个操作要么同时执行成功,要么同时执行失败。

数据库事务的ACID性质

  • Atomic:原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
  • Consistent:一致性,事务完成后,所有数据的状态都是一致的,即该人的账户减少了100,商店的账户必须增加100
  • Isolation:隔离性,比如两个人从同一个账户取款,这两个事务对数据的修改必须相互隔离,具体隔离策略后面具体讲解。
  • Duration:持久性,事务完成后,对数据库数据的修改必须被持久化存储。

数据库的隔离级别

在单个事务中,不需要做隔离,所谓数据库隔离级别是针对在并发事务的情况下,解决导致的一系列问题,这些问题包括:脏读、不可重复读、幻读,具体隔离级别如下图:

隔离级别脏读不可重复读幻读
SERIALIZABLE(串行化)避免避免避免
REPEATABLE READ(可重复读)避免避免允许
READ COMMITED(读已提交)避免允许允许
READ UNCOMMITED(读未提交)允许允许允许

SERIALIZABLE(串行化)

当两个事务同时操作数据库中相同数据时,如果第一个事务已经在访问该数据,第二个事务只能停下来等待,必须等到第一个事务结束后才能恢复运行。因此这两个事务实际上是串行化方式运行。

REPEATABLE READ(可重复读)

一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,但是不能看到其他事务对已有记录的更新。

READ COMMITTED(读已提交数据)

一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,而且还能看到其他事务已经提交的对已有记录的更新。

READ UNCOMMITTED(读未提交数据)

一个事务在执行过程中可以看到其他事务没有提交的新插入的记录,而且还能看到其他事务没有提交的对已有记录的更新。

没有事务隔离级别导致的问题

如果没有数据库的隔离级别,数据库的数据是实时变化的,即每个事务都可以读到其它事务修改后的数据,下面结合实例介绍每个场景的问题。

脏读

定义:读到未提交更新的数据

时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务
时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务
时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务
时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务
时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务
时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务
时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务
时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务
时间点事务1事务2
T1开始事务
T2开始事务
T3查询账户余额为1000
T4取出100后金额为900
T5查询账户金额为900(脏读)
T6撤销事务,余额恢复为1000
T7存入100元后,金额变为1000
T8提交事务

如上事务1取出金额100后又回滚了,即啥都没做,但事务2存入了100,但最终的金额确还是1000,正确应该是1100。
在T5时间节点出现了脏读,如果数据库配置了隔离级别为SERIALIZABLE、REPEATABLE READ、READ COMMITTED,在事务1没有提交的时候,事务2读取的都是原来的值就不会出现问题。

不可重复读

定义:在同一个数据中,两次读取到的数据不一致,读到了其他数据提交更新的数据

T1开始事务
T2开始事务
T3查询账户余额为1000
T4查询账户余额为1000
T5取出100后金额为900
T6提交事务
T7查询账户余额为900(与T4读取的不一致)
T1开始事务
T2开始事务
T3查询账户余额为1000
T4查询账户余额为1000
T5取出100后金额为900
T6提交事务
T7查询账户余额为900(与T4读取的不一致)
T1开始事务
T2开始事务
T3查询账户余额为1000
T4查询账户余额为1000
T5取出100后金额为900
T6提交事务
T7查询账户余额为900(与T4读取的不一致)
T1开始事务
T2开始事务
T3查询账户余额为1000
T4查询账户余额为1000
T5取出100后金额为900
T6提交事务
T7查询账户余额为900(与T4读取的不一致)
T1开始事务
T2开始事务
T3查询账户余额为1000
T4查询账户余额为1000
T5取出100后金额为900
T6提交事务
T7查询账户余额为900(与T4读取的不一致)
T1开始事务
T2开始事务
T3查询账户余额为1000
T4查询账户余额为1000
T5取出100后金额为900
T6提交事务
T7查询账户余额为900(与T4读取的不一致)
T1开始事务
T2开始事务
T3查询账户余额为1000
T4查询账户余额为1000
T5取出100后金额为900
T6提交事务
T7查询账户余额为900(与T4读取的不一致)
T1开始事务
T2开始事务
T3查询账户余额为1000
T4查询账户余额为1000
T5取出100后金额为900
T6提交事务
T7查询账户余额为900(与T4读取的不一致)

事务2的两次读取到的数据不一致,第二次读取到了事务1提交的数据

幻读

定义:读取到另一个事务已提交插入或删除的数据。

T1开始事务
T2开始事务
T3统计一年级1班所有的学生人数为40人
T4一年级1班新增一名学生
T5提交事务
T6再次统计一年级1班的所有学生人数为41人
T1开始事务
T2开始事务
T3统计一年级1班所有的学生人数为40人
T4一年级1班新增一名学生
T5提交事务
T6再次统计一年级1班的所有学生人数为41人
T1开始事务
T2开始事务
T3统计一年级1班所有的学生人数为40人
T4一年级1班新增一名学生
T5提交事务
T6再次统计一年级1班的所有学生人数为41人
T1开始事务
T2开始事务
T3统计一年级1班所有的学生人数为40人
T4一年级1班新增一名学生
T5提交事务
T6再次统计一年级1班的所有学生人数为41人
T1开始事务
T2开始事务
T3统计一年级1班所有的学生人数为40人
T4一年级1班新增一名学生
T5提交事务
T6再次统计一年级1班的所有学生人数为41人
T1开始事务
T2开始事务
T3统计一年级1班所有的学生人数为40人
T4一年级1班新增一名学生
T5提交事务
T6再次统计一年级1班的所有学生人数为41人
T1开始事务
T2开始事务
T3统计一年级1班所有的学生人数为40人
T4一年级1班新增一名学生
T5提交事务
T6再次统计一年级1班的所有学生人数为41人

事务2第一次统计人数为40人,第二次统计为41人,两次统计的结果不一致,同样如果T4时间节点转走一名学生,也会出现不一致

不可重复读和幻读看起来比较类似,都是一个事务里面读取到两次不同的结果
本质的区别是:不可重复读是由于数据更新导致数据不一致导致,幻读是由于插入或删除了数据导致的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值