事务的隔离级别的一些理解:可重复读出现不可重复读的问题的原因

1.事务的隔离级别

  •      串行化
  •      可重复读
  •      读已提交
  •      读未提交

2.可重复读 

在这里,程序员普遍常用的数据库还是MySQL,MySQL默认隔离级别是 可重复读,今天我们就来讲解一下可重复读,可能出现的问题。

3.问题

问题的来源:是在有一天我写代码,对service添加了事务操作,我发现可重复读,居然可以读取到并发的其他事务已经提交的值,这不就出现了不可重复读的问题了嘛。

我查阅了大量网上的资源,都说可重复读不可能出现不可重复读的问题,问了AI,也没有解决。

4.解答

问题的解答:还是查询到一个大佬的博客。

首先可重复读:确实只的就是你在一个事务里,查询只能看到和你当前版本一样和之前已经提交过的版本的数据。

原理就是:在事务开启的时候,会创建一个内存快照视图,存储数据库当前的状态。当别的事务进行修改提交以后,你重复查询你刚刚查过的那一行数据,是不会变化的。

重点来了

这里就要牵扯到里面的一个 小小的机制

        4.1    "当前读"

                        当前读,就是直接去读数据库别人已经提交的最新的值。

        4.2    "快照读"

                          快照读就是 读取创建视图 视图里的值。

我们在同一个事务,想要避免不可重复读,那么读取的 都是 快照读,这就保证了,不会被其它的事务所干扰收到影响。

什么时候是当前读?什么时候是快照读?

当执行update、delete、insert 语句的时候,由于必须要与数据库最新的值进行打交道,所以用的都是当前读。

只有select 才是快照读。

回到问题

为什么我的可重复读,发生了不可重复读的问题?

是因为我在查询前使用了 update语句,发生了当前读,把更新后的数据更新到当前快照里,也就是创建了当前的视图快照,变化之后的版本,当你再使用select 进行查询,发现版本与当前事务版本是一致的,当然可以查询到,本事务内存快照发生的变化。 

当然这里面细节很复杂。我这只是讲了一些表面是这么回事。

5.乐观锁的问题

关于乐观锁,不也是先查,在修改,那这里为什么就不会发生 当前读,读取到别人所提交的 versio,然后满足乐观锁条件进行修改呢。是因为,乐观锁是先查了第一遍,然后内存快照视图就已经创建了,然后带着这条数据去更新,这里也是用当前读来查询的,可以查到版本已经不一致了,没有可以更改的行了,然而别人更新过了,你的期望版本已经不对,所以对数据库是没有进行更新的,所以内存快照,当然没有变化,这就是可重复读的机制,select读取内存快照发现 ,版本并没有更改,如果你不把事务隔离级别调成读已提交,那么,它将一直读取到没有发生改变的值。改成读已提交后,才能够每次查询都会创建一个新的视图,也就是读取其他事务已经提交过后的值。查询到最新的版本,进行修改。

你可能感兴趣的:(自我理解,oracle,数据库)