脏读、幻读与不可重复读[通俗易懂]

脏读、幻读与不可重复读

大家好,又见面了,我是全栈君。

最近在读 《MySQL 技术内幕 InnoDB 存储引擎》,里面提到的各种概念都很新鲜,以前听说过脏读、幻读、不可重复读,但是对于概念不甚了解,于是查了一下,这里做个笔记。

数据库事务特征

数据库事务特征,即 ACID:

A Atomicity 原子性

事务是一个原子性质的操作单元,事务里面的对数据库的操作要么都执行,要么都不执行,

C Consistent 一致性

在事务开始之前和完成之后,数据都必须保持一致状态,必须保证数据库的完整性。也就是说,数据必须符合数据库的规则。

I Isolation 隔离性

数据库允许多个并发事务同事对数据进行操作,隔离性保证各个事务相互独立,事务处理时的中间状态对其它事务是不可见的,以此防止出现数据不一致状态。可通过事务隔离级别设置:包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)

D Durable 持久性

一个事务处理结束后,其对数据库的修改就是永久性的,即使系统故障也不会丢失。

MySQL 数据隔离级别

首先 MySQL 里有四个隔离级别:Read uncommttied(可以读取未提交数据)、Read committed(可以读取已提交数据)、Repeatable read(可重复读)、Serializable(可串行化)。

在 InnoDB 中,默认为 Repeatable 级别,InnoDB 中使用一种被称为 next-key locking 的策略来避免幻读(phantom)现象的产生。

使用 select @@tx_isolation; 可以查看 MySQL 默认的事务隔离级别。

不同的事务隔离级别会导致不同的问题:

脏读、幻读与不可重复读[通俗易懂]

脏读、幻读、不可重复读的概念

脏读

所谓脏读是指一个事务中访问到了另外一个事务未提交的数据,如下图:
脏读、幻读与不可重复读[通俗易懂]
如果会话 2 更新 age 为 10,但是在 commit 之前,会话 1 希望得到 age,那么会获得的值就是更新前的值。或者如果会话 2 更新了值但是执行了 rollback,而会话 1 拿到的仍是 10。这就是脏读。

幻读

一个事务读取2次,得到的记录条数不一致:
脏读、幻读与不可重复读[通俗易懂]
上图很明显的表示了这个情况,由于在会话 1 之间插入了一个新的值,所以得到的两次数据就不一样了。

不可重复读

一个事务读取同一条记录2次,得到的结果不一致:

脏读、幻读与不可重复读[通俗易懂]
由于在读取中间变更了数据,所以会话 1 事务查询期间的得到的结果就不一样了。

解决方案

解决方案也就是上文提到的四种隔离级别,他们可以最大程度避免以上三种情况的发生:

未授权读取

也称为读未提交(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。

授权读取

也称为读提交(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。

可重复读取(Repeatable Read)

可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。

序列化(Serializable)

序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

参考

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/111668.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • apache2虚拟主机实现一个服务器绑定多个域名[通俗易懂]

    apache2虚拟主机实现一个服务器绑定多个域名[通俗易懂]1.apache2的配置首先要配置好apache2,如果未配置,请参考我之前的博文:lamp的配置2.域名的解析将全部域名的www和@的A记录解析到云服务器的IP3.虚拟主机的配置1.配置httpd.conf如果etc/httpd/conf/httpd.conf存在,则配置此httpd.conf如果etc/httpd/conf/httpd.conf不存在,此时需要我们在/etc/apache2下

    2022年9月18日
    0
  • 关于【ExecuteReader: Connection 属性尚未初始化】的错误提示解决方案「建议收藏」

    关于【ExecuteReader: Connection 属性尚未初始化】的错误提示解决方案「建议收藏」遇到这种错误,很大概率是因为缺少SqlCommand里的两个参数。找到【SqlCommandmycmd=newSqlCommand();】这条语句,SqlCommand()有两个带传入的参数:一个是定义查询语句的sql, 另一个是定义数据库连接的conn以下为部分代码片段,仅供理解:stringsql=”select*fromInformationwhereUsername='”+Username+”‘andPassword='”+Passw.

    2022年6月20日
    19
  • 二分归并排序算法_并归排序法

    二分归并排序算法_并归排序法#include<iostream>#include<climits>usingnamespacestd;voidMerge(intSourceArry[],intStart,intMid,intEnd){ intlen1,len2;…

    2022年10月22日
    0
  • Sping 源码深度解析——容器的功能扩展 【学习笔记】

    我为什么 看的不够远,因为高度不够!学习和整理总结Spring容器的功能扩展,本文为学习笔记,其中有一些内容是自己的思考总结!一、两种Spring中bean加载的方式第一种# 第一种使用 BeanFactory 以及它默认的实现类 XmlBeanFactoryBeanFactory bf = new XmlBeanFactory(new ClassPathReso…

    2022年2月27日
    35
  • java怎么求数组的和_java求和函数写法

    java怎么求数组的和_java求和函数写法Java经典题目之一,数组的各种求和,今天小编就用一些例子带大家了解一下其中详情。基础求和#includeusingnamespacestd;//数组求和//方法一:时间复杂度为O(n),额外空间为(n)intArraySum(intarr[],intn){intsum=0;for(inti=0;i{sum+=arr[i];}returnsum;}//方法二…

    2022年10月2日
    1
  • sql server 连接查询_连表查询语句

    sql server 连接查询_连表查询语句SQL的连表查询2017年08月31日15:58:49阅读数:176SQL的连表查询连接查询包括合并、内连接、外连接和交叉连接,如果涉及多表查询,了解这些连接的特点很重要。只有真正了解它们之间的区别,才能正确使用。1、UnionUNION操作符用于合并两个或多个SELECT语句的结果集。UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派…

    2022年9月14日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号