对于数据库中脏读、不可重复读以及幻读的理解

个人笔记,仅供参考。欢迎交流。

前提

首先明确四个隔离等级
读未提交:

可以查询出事务中没有提交的数据,读最新和没有确认(提交)的数据

读已提交:

可以查询已经提交的事务数据,读最新的数据

重复读:

它跟读已提交的区别在于,它可以做到(不是一定会,也可以读最新的即:当前读)多次读取某时刻(称为快照)的数据,也就是多次读会读到相同的数据,而不是最新数据

串行化:串行执行事务,如果遇到写同样数据造成冲突,事务会串行执行,一个一个提交

两种锁

共享锁S:

        可以被其他事务读取,不能写

排它锁X:

        不能被其他事务任何操作,包括读取


对于数据库中脏读、不可重复读以及幻读的理解

脏读

脏读就是读取了没有提交的数据,只在读未提交等级出现。

不可重复读

在读取数据时会读到最新的数据而不是想要读取的某时刻数据。

举个例子:假设超市活动设定在 00:00:00 时余额大于 500 的用户送 1000 块。在23:59:59 有两个事务 A ( 检测活动 )、B( 处理充钱 )都开启了。小明充的钱在 00:00.01 时刻完成,也就是事务( B )提交。 而事务 A 因为处理某些问题导致在 00:00:02 又进行了一次查询,结果把小明也算成了符合的用户。而正常逻辑应该让 A 读取的数据仍然为 23:59:59 的数据。

解决方式就是切换重复读隔离等级,使用快照读。

幻读

幻读就是查询第一次有 8 条,相同语句再查一次变成 9 条了(因为别的事务提交造成)。

在重复读隔离等级下有 MVCC 机制和 next-key lock 机制来解决幻读。

在重复读下有如下两种读:

当前读(一致性锁定读)

当前读是基于 next-key lock (index lock 和 间隙锁),当使用当前读时对索引加排它锁,其他事务无法进行任何操作。

快照读(一致性非锁定读)

快照读基于 MVCC (多版本并发控制)。简单来说每个事务有一个版本 id ,当使用快照读时会记录: maxId、minId 以及一个活跃事务 id 集合 ids。然后在此次读中仅会显示所有事务 id 范围符合: (id < minId OR (minId < id < maxId AND id not in ids)) 的版本才会视为可见。

可以理解为在这个事务触发之前的事务,或者已经完成提交的事务,这两类事务才会视为可见,其余的事务屏蔽他们的影响。

这两种读分别是通过不允许其他事务修改和读取一个快照来解决幻读。

但是仍然有一种情况会出现幻读:

开启 A、B 两个事务,在 A 事务进行快照读,然后在 B 事务进行当前读并且插入一条新数据,如果 A 事务此时快照读不会出现幻读,并且如果 A 事务进行当前读,由于 B 事务已经获取排它锁, A 事务会被阻塞等待 B 事务结束,所以也不会出现幻读。

下一步,B 事务提交。此时 A 事务查询快照读仍然不会幻读,但如果此时 A 事务进行当前读,就会出现幻读现象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值