数据库产生脏读、不可重读读、幻读的原因

在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
对于会对数据修改的操作(update、insert、delete)都是采用当前读的模式。

当执行select操作是innodb默认会执行快照读,会记录下这次select后的结果,之后select 的时候就会返回这次快照的数据,即使其他事务提交了不会影响当前select的数据,这就实现了可重复读了。快照的生成当在第一次执行select的时候,也就是说假设当A开启了事务,然后没有执行任何操作,这时候B insert了一条数据然后commit,这时候A执行 select,那么返回的数据中就会有B添加的那条数据。之后无论再有其他事务commit都没有关系,因为快照已经生成了,后面的select都是根据快照来的。
使用 MVCC 读取的是快照中的数据,这样可以减少加锁所带来的开销。

怎么判断快照读和当前读:

快照读:最简单的select操作,属于快照读,不加锁
select * from table where id = 1;

当前读:特殊的读与增删改操作,属于当前读,会读取数据库原本的数据,加锁
select * from table where xxx lock in share mode; (共享锁)
select * from table where xxx for update;
insert into table values()
update table set xxx where xxx
delete form table where xxx

幻读产生的原因只有当前读才能出现幻读

产生的前提条件:必须是InnoDB引擎在可重复读隔离级别,使用当前读时。

幻读的表现:一个事务(同一个read view)在前后两次查询同一范围的时候,后一次查询看到了前一次查询没有看到的行(表示这时候有新行的insert(插入))。
tips:为什么必须是insert呢?
因为delete和update产生的是不可重复读(与脏读幻读并列的三大问题之一),通过行锁锁定之后,就可以避免对当前行的修改影响数据读取了。
但是行锁只能锁住行,即使把所有的行记录都上锁,也阻止不了新插入的记录。

两点需要说明:
  1、在可重复读隔离级别下,普通查询是快照读,是不会看到别的事务插入的数据的,幻读只在当前读下才会出现。
  2、幻读专指新插入的行,读到原本存在行的更新结果不算(只有读到新插入的数据才算幻读,读到原数据的修改不算)。因为当前读的作用就是能读到所有已经提交记录的最新值。

如何解决幻读

将两行记录间的空隙加上锁,阻止新记录的插入;这个锁称为间隙锁。
间隙锁与间隙锁之间没有冲突关系。跟间隙锁存在冲突关系的,是往这个间隙中插入一个记录这个操作。

脏读:就是读到了还没commit的数据(因为事务没有提交就可能回滚),一旦回滚就是脏读,在读未提交这个隔离级别容易出现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值