看图说话,脏读、不可重复读、幻读分别是什么?

JAVA herman 197浏览 0评论

事务的隔离性是一个一说就明白,一讲就糊涂,一讨论就吵架的话题。很多人对概念记得很牢,但是你让他们解释一下,脏读、不可重复读、幻读,他们却解释不出来,尤其是不可重复读和幻读两种搞不清或者搞混淆。其实它们很简单,可能就是你的方法没找对。

数据库的四种隔离级别,Read Uncommitted(读未提交),Read Committed(读已提交),Repeatable Read(可重复读),Serializable(串行化)可以产生脏读、不可重复读、幻读等问题。下面我来说说脏读、不可重复读、幻读分别是怎样产生的!

脏读

所谓脏读是指一个事务中访问到了另外一个事务未提交的数据,如下图所示:

脏读

需要说明的是脏读、不可重复读、幻读都是发生在两个事务以上的情况。只有一个事务是不存在脏读、不可重复读、幻读的。两个事务也就是两个回话,也就是多个线程同时操作 id=1 的记录。假设两个会话开启前数据库中 table 表中 id=1 的记录行里面的列 age 值为 5。会话 1 和回话 2 一开始都开启了手动提交的事务(只有执行 commit 命令才会提交数据的修改),会话 2 首先更新了 table 中 id=1 的记录行的 age 列的值为 10(更新前值为 5),在会话 2 执行 commit 提交前,会话 1 通过 select 语句查询 id=1 的记录行中 age 列的值,这时候如果存在脏读,则会话 1 读取到的 age 的值是 10 而不是 5 了,虽然会话 2 的更新还没有提交。那么脏读存在什么问题那?如果会话 2 最后提交了,那么会话 1 虽然在会话 2 还没提交就读取到了修改的值,但是也没什么影响;但是如果会话1读取到会话 2 没有提交的数据后,会话 2 执行了 rollback,也就是没有把修改刷新到数据库,但是会话 1 已经使用了修改的数据,这样程序就会出错。

不可重复读

所谓不可重复读是指在一个事务内根据同一个条件对行记录进行多次查询,但是搜出来的结果却不一致。发生不可重复读的原因是在多次搜索期间查询条件覆盖的数据被其他事务修改了。看下图来方便我们理解不可重复读。

不可重复读

如上图假设数据库表 table 里面 id=1 的记录行中 age 列一开始值为 5,然后会话 1 和会话 2 分别开启了一个事务,会话 1 首先查询id=1的记录中age字段值为5,然后会话 2 修改 id=1 的记录中 age 的值为 10 然后提交了事务,然后会话 1 再次搜出 id=1 的记录中 age 的值,如果出现了不可重复读,则这时候搜出来的 age 的值为 10 而不是 5。需要注意的是会话1两次查询是在同一个事务内进行的,期间事务并没有提交。不可重复读的存在显得不是那么不可容忍,毕竟读取的是已经提交了的数据。

幻读

所谓幻读是指同一个事务内多次查询返回的结果集不一样(比如增加了或者减少了行记录)。比如同一个事务 A 内第一次查询时候有 n 条记录,但是第二次同等条件下查询却又 n+1 条记录,这就好像产生了幻觉,为啥两次结果不一样那。其实和不可重复读一样,发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据。不同在于不可重复读是同一个记录的数据内容被修改了,幻读是数据行记录变多了或者少了:

幻读

如上图假设表 table 里面一开始有一个 id=3 的记录,会话 1 首先开启了一个事务,然后查找 id>2 的记录,会发现结果只有一个记录,然后会话 2 开启事务插入了 id=5 的一个记录,然后提交。这时候会话1再次查找 id>2 的记录,如果存在幻读,则这时候会话1会看到两条记录。

总结:脏读是指一个事务读取到了其他事务没有提交的数据,不可重复读是指一个事务内多次根据同一个查询条件查询出来的同一行记录的值不一样,幻读是指一个事务内多次根据同个条件查出来的记录行数不一样。为了解决事务并发带来的问题,才有了事务规范中的四个事务隔离级别,不同隔离级别对上面问题部分或者全部做了避免。

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847,QQ3群:187424846。QQ群进群密码:xttblog,想加微信群的朋友,可以微信搜索:xmtxtt,备注:“xttblog”,添加助理微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » 看图说话,脏读、不可重复读、幻读分别是什么?