事务的隔离级别的一些理解:可重复读出现不可重复读的问题的原因
1.事务的隔离级别
- ? ? ?串行化
- ? ? ?可重复读
- ? ? ?读已提交
- ? ? ?读未提交
2.可重复读?
在这里,程序员普遍常用的数据库还是MySQL,MySQL默认隔离级别是 可重复读,今天我们就来讲解一下可重复读,可能出现的问题。
3.问题
问题的来源:是在有一天我写代码,对service添加了事务操作,我发现可重复读,居然可以读取到并发的其他事务已经提交的值,这不就出现了不可重复读的问题了嘛。
我查阅了大量网上的资源,都说可重复读不可能出现不可重复读的问题,问了AI,也没有解决。
4.解答
问题的解答:还是查询到一个大佬的博客。
首先可重复读:确实只的就是你在一个事务里,查询只能看到和你当前版本一样和之前已经提交过的版本的数据。
原理就是:在事务开启的时候,会创建一个内存快照视图,存储数据库当前的状态。当别的事务进行修改提交以后,你重复查询你刚刚查过的那一行数据,是不会变化的。
重点来了
这里就要牵扯到里面的一个 小小的机制
? ? ? ? 4.1? ? "当前读"
? ? ? ? ? ? ? ? ? ? ? ? 当前读,就是直接去读数据库别人已经提交的最新的值。
? ? ? ? 4.2? ? "快照读"
? ? ? ? ? ? ? ? ? ? ? ? ? 快照读就是 读取创建视图 视图里的值。
我们在同一个事务,想要避免不可重复读,那么读取的 都是 快照读,这就保证了,不会被其它的事务所干扰收到影响。
什么时候是当前读?什么时候是快照读?
当执行update、delete、insert 语句的时候,由于必须要与数据库最新的值进行打交道,所以用的都是当前读。
只有select 才是快照读。
回到问题
为什么我的可重复读,发生了不可重复读的问题?
是因为我在查询前使用了 update语句,发生了当前读,把更新后的数据更新到当前快照里,也就是创建了当前的视图快照,变化之后的版本,当你再使用select 进行查询,发现版本与当前事务版本是一致的,当然可以查询到,本事务内存快照发生的变化。?
当然这里面细节很复杂。我这只是讲了一些表面是这么回事。
5.乐观锁的问题
关于乐观锁,不也是先查,在修改,那这里为什么就不会发生 当前读,读取到别人所提交的 versio,然后满足乐观锁条件进行修改呢。是因为,乐观锁是先查了第一遍,然后内存快照视图就已经创建了,然后带着这条数据去更新,这里也是用当前读来查询的,可以查到版本已经不一致了,没有可以更改的行了,然而别人更新过了,你的期望版本已经不对,所以对数据库是没有进行更新的,所以内存快照,当然没有变化,这就是可重复读的机制,select读取内存快照发现 ,版本并没有更改,如果你不把事务隔离级别调成读已提交,那么,它将一直读取到没有发生改变的值。改成读已提交后,才能够每次查询都会创建一个新的视图,也就是读取其他事务已经提交过后的值。查询到最新的版本,进行修改。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!