脏读 订阅
脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的,值得注意的是,脏读一般是针对于update操作的。 展开全文
脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的,值得注意的是,脏读一般是针对于update操作的。
信息
别    称
无效数据的读出
出    处
sql语句
拼    音
zang du
中文名
脏读
外文名
Read out of invalid data
网络规划规划设计
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
收起全文
精华内容
下载资源
问答
  • SQL中的脏读、不可重复读、幻读
    2021-03-22 17:53:20

    一、数据库事务隔离级别

     

    数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read committed 、Repeatable read 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读 这几类问题。

     

    √: 可能出现    ×: 不会出现

     脏读不可重复读幻读
    Read uncommitted
    Read committed×
    Repeatable read××
    Serializable×××

     

    注意:我们讨论隔离级别的场景,主要是在多个事务并发 的情况下,因此,接下来的讲解都围绕事务并发。

    Read uncommitted 读未提交

    公司发工资了,领导把5000元打到singo的账号上,但是该事务并未提交,而singo正好去查看账户,发现工资已经到账,是5000元整,非常高 兴。可是不幸的是,领导发现发给singo的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后singo实际的工资只有 2000元,singo空欢喜一场。

     

     

    出现上述情况,即我们所说的脏读 ,两个并发的事务,“事务A:领导给singo发工资”、“事务B:singo查询工资账户”,事务B读取了事务A尚未提交的数据。

    当隔离级别设置为Read uncommitted 时,就可能出现脏读,如何避免脏读,请看下一个隔离级别。

    Read committed 读提交

    singo拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把singo工资卡的2000元转到另一账户,并在 singo之前提交了事务,当singo扣款时,系统检查到singo的工资卡已经没有钱,扣款失败,singo十分纳闷,明明卡里有钱,为 何......

    出现上述情况,即我们所说的不可重复读 ,两个并发的事务,“事务A:singo消费”、“事务B:singo的老婆网上转账”,事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。

    当隔离级别设置为Read committed 时,避免了脏读,但是可能会造成不可重复读。

    大多数数据库的默认级别就是Read committed,比如Sql Server , Oracle。如何解决不可重复读这一问题,请看下一个隔离级别。

    Repeatable read 重复读

    当隔离级别设置为Repeatable read 时,可以避免不可重复读。当singo拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),singo的老婆就不可能对该记录进行修改,也就是singo的老婆不能在此时转账。

    虽然Repeatable read避免了不可重复读,但还有可能出现幻读 。

    singo的老婆工作在银行部门,她时常通过银行内部系统查看singo的信用卡消费记录。有一天,她正在查询到singo当月信用卡的总消费金额 (select sum(amount) from transaction where month = 本月)为80元,而singo此时正好在外面胡吃海塞后在收银台买单,消费1000元,即新增了一条1000元的消费记录(insert transaction ... ),并提交了事务,随后singo的老婆将singo当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,singo的老婆很诧异,以为出 现了幻觉,幻读就这样产生了。

    注:MySQL的默认隔离级别就是Repeatable read。

    Serializable 序列化

    Serializable 是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。

     

     

    二、脏读、幻读、不可重复读

    1.脏读:
    脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。


    2.不可重复读:
    是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。(即不能读到相同的数据内容)
    例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题。


    3.幻读:
    是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象
    发生了幻觉一样。
    例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。

    更多相关内容
  • 数据库锁(行锁,表锁,共享锁,排他锁) 行锁 我们知道mysql的Innodb引擎是支持行锁的,与Oracle不同,mysql的行锁是通过索引加载的,即行锁是加载索引响应的行上的,要是对应的SQL语句没有索引,则会走表锁。...
  • 数据库的脏读、不可重复读、幻读都和事务的隔离性有关。所以先了解一下事务的4大特性。  事务的4大特性(ACID):  1、原子性(Atomicity):事务是数据库的逻辑工作单位,它对数据库的修改要么全部执行,要么...
  • 脏读 定义:A事务执行过程中B事务读取了A事务的修改,但是A事务并没有结束(提交),A事务后来可能成功也可能失败。 比喻:A修改了源代码并且并没有提交到源代码系统,A直接通过QQ将代码发给了B,A后来取消了修改。 ...
  • 脏读可导致同一记录得到两个版本,或是完全地丢失一条记录。在同一事务中多次重新运行同一查询后,可能会出现幻读。最近MongoDB登上了Reddit的头条,因为MongoDB的核心开发者DavidGlasser痛苦地认识到MongoDB默认会...
  • 什么是脏读不可重复读幻影读,JAVA程序对MYSQL数据库加锁实验
  • 四种隔离级别 隔离级别 描述 READ UNCOMMITED 读未提交数据 允许事务读取未被其他事务提交的变更,脏读,不可重复读和幻读问题都会出现 READ COMMITED读已提交数据 只允许事务读取已被其他事务提交的变更,可以避免...

    事务的ACID属性

    原子性(Atomictiy)原子性是指事务是一个不可分割的单位,事务中的操作要么都发生,要么都不发生。

    简单的来说就是在事务操作中,比如我通过两条SQL 改两条数据,要么这两个操作都完成,要么都不完成就回滚。

    一致性(Consistency)事务必须从一个一致性状态变换到另一个一致性状态。

    比如转账操作,从A转给B 100元钱,那么A 少100,B 收到100,即这个转账操作就是从未转账状态到转账成功状态,类似于事务一致性的体现。

    隔离性(Isolation)事务的隔离性,是指一个事务的执行不被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

    类似于多线程中的线程资源竞争问题。

    持久性(Durability)一个事务一旦被提交,他对数据库中数据的改变是永久性的,接下来的其他操作对数据库故障不应该对其有任何影响。

    事务操作完数据,这个数据就被持久化了,无论数据库断电、还是故障、等都不应该再改变操作完的数据,体现其持久性。

    事务并发引起的问题

    事务并发一般会引起如下三个问题,分别是 脏读、不可重复读、幻读,这三个里面,脏读是我们必须要解决的。

    1.脏读

    对于两个事务,T1 和 T2, T1 读取了已被T2 更新,但是还没有被提交的字段,之后,若T2 回滚,T1 读取的数据就是临时的且无效的数据。

    比方说,改一条数据,事务T1 用于操作改数据,T2 用于读取该后的数据,当T1 在改完还未提交事务时,T2 这个时候去读取T1 的数据,居然读出来时改之后的,这显然是有问题的,因为T1 有可能操作失败回滚,或者说T1 还未改完数据,这时T2 去读未改完的数据显然是不合理的。

    2.不可重复读

    对于两个事务,T1,T2, T1 读取了一个字段,然后T2 更新了该字段,之后T1 再去读取同一个字段,值就不一样了。

    例如,我在买东西的时候,看到库存不足了,这个时候我没有关浏览器,再次刷新了浏览器,结构看到有库存了,这时因为后台数据库增加了库存,而我又没有断开此次事务连接,这样就读取到了最新的数据。(这种情况就是不可重复读问题)

    可重复读,意思是说我一个数据库事务连接 没有断开,读取的就是我这个事务之前读取的数据,数据更新数据(事务提交),我也不应该读取事务提交后的数据,因为我这都是在一个事务中的。就说不管更新数据的事务有没有提交,只要我当前查询的事务没有关闭,就会读取之前我查询出来的状态,不管另一个更新的事务操作。

    我们为了解决不可重复读问题,需要让他可重复读,然而实际上大多数情况 不可重复读问题是 不需要解决的。

    什么又叫可重复读呢?

    意思就算另一个事务,改了数据(即使他commit了),如果 当前 读取数据的事务操作没有关闭,则读取的数据就还是之前的数据,如图:

    这种模式下,想要读取提交后的数据,必须重新起一个事务。

    3.幻读

    对于两个事务 T1,T2 T1从一张表中读取了一个字段后,然后T2在表中 插入了一些新的行,之后,如果T1 再次读取同一个表,就会多出几行。

    这里它强调的是插入操作,例如我一个事务T1读数据读出了100条,另一事务T2此时正在向此表插入数据,这时我第一个事务T1读出来就比100条多了,这种情况就是幻读。

    总结

    注意: 不可重复读,指的是 更新 操作,而幻读,指的是 插入 操作。

    一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务的隔离级别,不同隔离级别应对不同的干扰程度。

    隔离级别越高,数据一致性就越好,但并发性就越弱,类似于多线程加锁,隔离性好但性能差。

    一般情况下,不可重复读问题是可以接受的,一般我们只需要解决脏读的问题。

    四种隔离级别

    隔离级别

    描述

    READ UNCOMMITED 读未提交数据

    允许事务读取未被其他事务提交的变更,脏读,不可重复读和幻读问题都会出现

    READ COMMITED读已提交数据

    只允许事务读取已被其他事务提交的变更,可以避免脏读,但不可重复读和幻读问题依然存在

    REPEATABLE READ 可重复读

    确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读问题,但幻读问题依然存在。

    SERIALLZABLE 串行化

    确保事务可以从一个表中读取相同约行,在这个事务持续期间,禁止其他事务对表执行插入更新删除操作,所有问题都可避免,但性能十分低下

    Oracle 支持2种事务隔离级别,READ COMMITED, SERIALIZABLE. 它默认隔离级别为 READ COMMITED.

    隔离级别越往下,则 一致性越好,并发性越差。

    一般情况下,脏读问题必须解决,不可重复读和幻读问题是可以接受的。

    Java 隔离级别演示

    如下代码

    一段查询代码,根据设置的隔离级别查询数据,隔离级别如下:

    TRANSACTION_REPEATABLE_READ 为可重复读,避免了脏读和可不可重复读问题.

    TRANSACTION_READ_UNCOMMITTED 读未提交数据,这种隔离级别存在脏读,会读取未提交的数据

    TRANSACTION_READ_COMMITTED 读已提交的数据,如果修改的数据未提交,则读出来还是老的修改之前的数据

    TRANSACTION_SERIALIZABLE 串行化,解决了脏读,不可重复读,幻读。 一般不用,因为并发效率低。

    查询更新的数据

    一般我们都会将隔离级别设置为 TRANSACTION_READ_COMMITTED, 这样更新的事务如果没有提交,则读取的都是之前的值,这里只会读取已提交的数据。

    @Test

    public void testTransactionSelect() {

    Connection conn = JDBCUtils.GetDBConnection();

    try {

    //获取取数据库的隔离级别,当前为TRANSACTION_REPEATABLE_READ

    //TRANSACTION_REPEATABLE_READ 为可重复读,避免了脏读和可不可重复读问题.

    //TRANSACTION_READ_UNCOMMITTED 读未提交数据,这种隔离级别存在脏读,会读取未提交的数据

    //TRANSACTION_READ_COMMITTED 读已提交的数据,如果修改的数据未提交,则读出来还是老的修改之前的数据

    conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

    System.out.println(conn.getTransactionIsolation());

    //取消自动提交数据

    conn.setAutoCommit(false);

    String sql = "SELECT `user`,`password`,balance FROM balance WHERE `user` = ?";

    DBCommand dbCommand = new DBCommand(conn);

    BalanceEntity balance1 = dbCommand.queryMethod(BalanceEntity.class, sql, "jerry");

    System.out.println(balance1);

    } catch (Exception ex) {

    ex.printStackTrace();

    }finally {

    try {

    conn.close();

    } catch (SQLException throwables) {

    throwables.printStackTrace();

    }

    }

    }

    更新数据操作

    如下更新操作中,将数据库中的balance改为6000,中途等待15秒后提交,那么在这15秒内,查询数据库中的数据依然是之前的值。

    @Test

    public void testTransactionUpdate() {

    Connection conn = JDBCUtils.GetDBConnection();

    DBCommand dbCommand = new DBCommand(conn);

    try {

    String sql = "UPDATE balance SET `balance` = ? WHERE `user`= ?";

    conn.setAutoCommit(false);

    int updateResult = dbCommand.updateMethod(conn, sql, 6000, "jerry");

    if (updateResult > 0) {

    System.out.println("更新数据成功!");

    }

    Thread.sleep(15000);

    conn.commit();

    } catch (Exception ex) {

    ex.printStackTrace();

    }finally {

    try {

    conn.close();

    } catch (SQLException throwables) {

    throwables.printStackTrace();

    }

    }

    }

    如之前的值为 2000 ,隔离级别设置为 TRANSACTION_READ_COMMITTED,那么在这15秒未提交的时间里,数据库查询结果和代码结果都是2000:

    数据库中查询结果

    代码中查询结果

    15秒后,数据提交,则查询结果如下:

    展开全文
  • 既然支持事务,那么就会有处理并发事务带来的问题:更新丢失、脏读、不可重复读、幻读;相应的为了解决这四个问题, 就产生了事务隔离级别:未提交读(Read uncommitted),已提交读(Read committed),可重复读...

    众所周知MySQL从5.5.8开始,Innodb就是默认的存储引擎,Innodb最大的特点是:支持事务、支持行级锁。 既然支持事务,那么就会有处理并发事务带来的问题:更新丢失、脏读、不可重复读、幻读;相应的为了解决这四个问题, 就产生了事务隔离级别:未提交读(Read uncommitted),已提交读(Read committed),可重复读(Repeatable read),可序列化(Serializable)。

    事务的特性:

    原子性:指处于同一个事务中的多条语句是不可分割的。即它对数据库的修改要么全部执行,要么全部不执行

    一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如转账,转账前两个账户余额之和为2k,转账之后也应该是2K。

    隔离性:指多线程环境下,一个线程中的事务不能被其他线程中的事务打扰 持久性:事务一旦提交,就应该被永久保存起来。

    持久性:事务一旦提交,就应该被永久保存起来。

    1、概念说明:

    更新丢失:最后的更新覆盖了其他事务之前的更新,而事务之间并不知道,发生更新丢失。更新丢失,可以完全避免,应用对访问的数据加锁即可。

    脏读(针对未提交的数据):一个事务在更新一条记录,未提交前,第二个事务读到了第一个事务更新后的记录,那么第二个事务就读到了脏数据,会产生对第一个未提交 数据的依赖。一旦第一个事务回滚,那么第二个事务读到的数据,将是错误的脏数据。

    不可重复读(读取数据本身的对比):一个事务在读取某些数据后的一段时间后,再次读取这个数据,发现其读取出来的数据内容已经发生了改变,就是不可重复读。

    幻读(读取结果集条数的对比):一个事务按相同的查询条件查询之前检索过的数据,确发现检索出来的结果集条数变多或者减少(由其他事务插入、删除的),类似产生幻觉。

    2、事务隔离级别:

    并发处理带来的问题中,更新丢失可以完全避免,由应用对数据加锁即可。脏读、不可重读度、幻读,其实都是数据库的一致性问题,必须由一定的事务隔离机制来解决。 其中一种方法是:不用加锁,通过一定的机制生成一个数据请求时间点的一致性快照,并用这个快照来提供一个界别的一致性读取。从用户的角度看,好像是数据库提偶拱了 统一数据的多个版本。这种技术叫做:数据库多版本并发控制,MVCC 多版本数据库。

    事务隔离的本质是使事务在一定程度上串行化执行,显然和并发机制是矛盾的。数据库的事务隔离越严格,并发负作用越小,代价越高(影响并发访问了呗)。

    为了解决隔离和并大的矛盾,IOS SQL92规定了4个隔离级别。(隔离==串行)

    5be58600080ba4b3bc9ad298e70c2b77.png

    大多数数据库默认的事务隔离级别是 Read Committed,比如 SQL Server , Oracle。但 MySQL 的默认隔离级别是 Repeatable Read。

    举例1:

    脏读(Read Uncommitted)

    通俗的讲,一个事务在处理过程中读取了另外一个事务未提交的数据。(你都还没提交,我就读到了你刚操作的数据,万一你回滚了怎么办,你说这脏不脏。)

    举例(事务B未提交,事务A却读到了事务B未提交的数据):

    92f71f028497d6ef1411542f95ab977a.png

    3.2 不可重复读(Non-repeatable Read)

    通俗的讲,一个事务范围内,多次查询某个数据,却得到不同的结果。

    与脏读的区别:脏读是读到未提交的数据,而不可重复读读到的却是已经提交的数据,但实际上是违反了事务的一致性原则。

    举例(事务B提交后,事务A却读到了事务B已提交的数据,导致事务A两次读到地数据不一致):

    797452e17ae3e80878b2516445569e9a.png

    3.3 幻读

    在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。

    事务A读取与搜索条件相匹配的若干行。事务B以插入或删除行等方式来修改事务A的结果集,然后再提交。

    举例(id主键唯一,事务A搜索id=10的数据,事务A搜索不到id=10的数据,然后事务B新增id=10的数据并提交,事务A更新id=10的数据却成功,插入id=10却失败,现在搜索id=10也有记录):

    aa7fda7b9d29aa2e4206ee87d0203237.png

    举例2:

    1. 脏读的情况:对于两个事务T1与T2,T1读取了已经被T2更新但是还没有提交的字段之后,若此时T2回滚,T1读取的内容就是临时并且无效的

    开启两个mysql客户端,并创建一张测试表transaction

    0f3b91dd2808b85598db150f27c347d2.png

    更改默认隔离级别REPEATABLE READ为READ UNCOMMITTED,用于测试

    SELECT @@tx_isolation; #查询隔离级别

    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; # 更改隔离级别

    afbd1807191cbeb0cf978eacce69f3ee.png

    两个客户端同时开启事务,其中一个事务做UPDATE操作,另一个事务做SELECT

    bc6284b3abde232d5a64fb511a226f11.png

    若此时黑色背景的客户端进行回滚,则白色背景的客户端读取的数据就是临时并且无效的。即脏读。

    2. 不可重复读: 对于两个事务T1和T2,T1读取了一个字段,然后T2更新了该字段并提交之后,T1再次提取同一个字段,值便不相等了。

    1b61cea7b9908b5451f06519b24ed3ec.png

    重复读取的结果不一致的情况发生。

    3. 幻读: 对于两个事务T1、T2,T1从表中读取数据,然后T2进行了INSERT操作并提交,当T1'再次读取的时候,结果不一致的情况发生。

    eea93b55258fcb92c59c42c56147c630.png

    展开全文
  • 事务隔离级别脏读幻读 In this article, we will discuss the Dirty Read concurrency issue and also learn the details of the Read Uncommitted Isolation Level. 在本文中,我们将讨论“ 脏读”并发问题,...

    事务隔离级别脏读幻读

    In this article, we will discuss the Dirty Read concurrency issue and also learn the details of the Read Uncommitted Isolation Level.

    在本文中,我们将讨论“ 脏读”并发问题,并了解“ 读未提交的隔离级别”的详细信息。

    A transaction is the smallest working unit that performs the CRUD (Create, Read, Update, and Delete) actions in the relational database systems. Relevant to this matter, database transactions must have some characteristics to provide database consistency. The following four features constitute the major principles of the transactions to ensure the validity of data stored by database systems. These are;

    事务是在关系数据库系统中执行CRUD(创建,读取,更新和删除)操作的最小工作单元。 与此相关的是,数据库事务必须具有某些特性以提供数据库一致性。 以下四个功能构成了事务的主要原理,以确保数据库系统存储的数据的有效性。 这些是;

    • Atomicity 一个 tomicity
    • Consistency çonsistency
    • Isolation 我这样
    • Durability d urability

    These four properties are also known as ACID principles. Let’s briefly explain these four principles.

    这四个属性也称为ACID原理。 让我们简要解释这四个原则。

    原子性 (Atomicity )

    This property is also known as all or nothing principle. According to this property, a transaction can not be completed partially, so if a transaction gets an error at any point of the transaction, the entire transaction should be aborted and rollbacked. Or, all the actions contained by a transaction must be completed successfully.

    此属性也称为“全部或全部”原则。 根据此属性,不能部分完成事务,因此,如果事务在事务的任何点出现错误,则应中止并回滚整个事务。 或者,必须成功完成事务包含的所有操作。

    一致性 (Consistency )

    According to this property, the saved data must not damage data integrity. This means that the modified data must provide the constraints and other requirements that are defined in the database.

    根据此属性,保存的数据不得破坏数据完整性。 这意味着修改后的数据必须提供数据库中定义的约束和其他要求。

    耐用性 (Durability)

    According to this property, the committed will not be lost even with the system or power failure.

    根据此属性,即使系统或电源出现故障,提交的内容也不会丢失。

    隔离 (Isolation )

    The database transactions must complete their tasks independently from the other transactions. This property enables us to execute the transactions concurrently on the database systems. So, the data changes which are made up by the transactions are not visible until the transactions complete (committed) their actions. The SQL standard describes three read phenomena, and they can be experienced when more than one transaction tries to read and write to the same resources.

    数据库事务必须独立于其他事务完成其任务。 此属性使我们能够在数据库系统上并发执行事务。 因此,在事务完成(提交)其操作之前,由事务构成的数据更改是不可见的。 SQL标准描述了三种读取现象,当多个事务尝试读取和写入相同的资源时可能会遇到这种现象。

    • Dirty-reads

      脏读
    • Non-repeatable reads

      不可重复读
    • Phantom reads

      幻影阅读

    什么是脏读? (What is Dirty Read?)

    The simplest explanation of the dirty read is the state of reading uncommitted data. In this circumstance, we are not sure about the consistency of the data that is read because we don’t know the result of the open transaction(s). After reading the uncommitted data, the open transaction can be completed with rollback. On the other hand, the open transaction can complete its actions successfully. The data that is read in this ambiguous way is defined as dirty data. Now we will explain this issue with a scenario:

    脏读取的最简单解释是读取未提交数据的状态。 在这种情况下,我们不确定所读取数据的一致性,因为我们不知道未完成交易的结果。 读取未提交的数据后,可以通过回滚完成未完成的事务。 另一方面,未清事务可以成功完成其操作。 以这种歧义方式读取的数据被定义为脏数据。 现在,我们将用一个场景来解释这个问题:

    Assuming we have a table as shown below that stores the bank account details of the clients.

    假设我们有一个下表,该表存储了客户的银行帐户详细信息。

    AccountNumber

    ClientName

    Balance

    7Y290394

    Betty H. Bonds

    $78.00

    账号

    客户名称

    平衡

    7Y290394

    贝蒂·H·邦兹

    $ 78.00

    In this scenario, Betty has $78.00 in her bank account, and the automatic payment system withdraws $45 from Betty’s account for the electric bill. At that time, Betty wants to check her bank account on the ATM, and she notices $33 in her bank account. However, if the electric bill payment transaction is rollbacked for any reason, the bank account balance will be turned to $78.00 again, so the data read by Betty is dirty data. In this case, Betty will be confused. The following diagram illustrates this dirty read scenario in a clearer manner.

    在这种情况下,Betty的银行帐户有$ 78.00,自动付款系统会从Betty的帐户中提取$ 45的电费。 当时,贝蒂想在自动柜员机上检查她的银行帐户,她发现自己的银行帐户中有33美元。 但是,如果由于任何原因而回扣了电费支付交易,则银行帐户余额将再次变为$ 78.00,因此Betty读取的数据是肮脏的数据。 在这种情况下,贝蒂会感到困惑。 下图以更清晰的方式说明了这种脏读情况。

    Read uncommitted isolation level explanation diagram.

    Now we will realize this scenario in practice with SQL Server. Firstly we will create the BankDetailTbl table that stores the bank account details of the clients.

    现在,我们将在SQL Server的实践中实现这种情况。 首先,我们将创建BankDetailTbl表,该表存储客户的银行帐户详细信息。

    CREATE TABLE BankDetailTbl
    (
      Id            INT
      PRIMARY KEY IDENTITY(1, 1), 
      AccountNumber VARCHAR(40), 
      ClientName    VARCHAR(100), 
      Balance       MONEY);
    

    As a second step, we will insert a sample row to it.

    第二步,我们将在其中插入一个示例行。

    INSERT INTO BankDetailTbl
    VALUES
    ('7Y290394', 'Betty H. Bonds', '78');
    

    Now we will execute the following queries, the Query-1 updates the balance value of the particular bank account, and then it will wait 20 seconds and rollback the data modification. At this moment, we will immediately execute the Query-2, and this query reads the modified but uncommitted data.

    现在,我们将执行以下查询,Query-1更新特定银行帐户的余额值,然后将等待20秒并回滚数据修改。 此时,我们将立即执行Query-2,此查询将读取已修改但未提交的数据。

    Query-1:

    查询1:

    BEGIN TRAN;
    UPDATE BankDetailTbl
    SET 
        Balance=Balance-45
    WHERE AccountNumber = '7Y290394';
    WAITFOR DELAY '00:00:20';
    ROLLBACK TRAN;
     
    SELECT *
    FROM BankDetailTbl
    WHERE AccountNumber = '7Y290394';
    

    Query-2:

    查询2:

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    BEGIN TRAN;
    SELECT *
    FROM BankDetailTbl
    WHERE AccountNumber = '7Y290394';
    COMMIT TRAN;
    

    SQL Server dirty read example.

    As a result, the data read by Query-2 was dirty because the data was returned to its first state because of the rollback process.

    结果,由于回滚过程使数据返回到其第一状态,因此Query-2读取的数据很脏。

    读未提交与读提交隔离级别 (The Read Uncommitted vs Read Committed Isolation Level)

    As we explained, a transaction must be isolated from other transactions according to the isolation property of the ACID transactions. In this context, isolation levels specify the isolation strategy of a transaction from the other transactions.

    正如我们所解释的,必须根据ACID事务的隔离属性将一个事务与其他事务隔离。 在这种情况下, 隔离级别指定一个事务与其他事务的隔离策略。

    什么是排他锁? (What is Exclusive Lock?)

    By default, SQL Server sets an exclusive lock for data that is being modified to ensure data consistency until the transaction is complete. So, it isolates the modified data from the other transaction.

    默认情况下,SQL Server为正在修改的数据设置排他锁,以确保数据一致性,直到事务完成为止。 因此,它将修改后的数据与其他事务隔离。

    Read uncommitted is the weakest isolation level because it can read the data which are acquired exclusive lock to the resources by the other transactions. So, it might help to avoid locks and deadlock problems for the data reading operations. On the other hand, Read Committed can not read the resource that acquires an exclusive lock, and this is the default level of the SQL Server.

    读取未提交是最弱的隔离级别,因为它可以读取通过其他事务获得的对资源的独占锁定的数据。 因此,这可能有助于避免数据读取操作的锁定和死锁问题。 另一方面, Read Committed无法读取获得排他锁的资源,这是SQL Server的默认级别。

    Now we will work on an example of this difference to figure this out. With the help of the Query-3, we will change the ClientName column value of a client. During this time, Query-4 tries to read the same client details, but Query-4 could not be read the data until the Query-3 completes the update action. At first, we will execute the Query-3.

    现在,我们将研究这种差异的一个例子,以解决这一问题。 借助Query-3,我们将更改客户端的ClientName列值。 在此期间,Query-4尝试读取相同的客户端详细信息,但是直到Query-3完成更新操作之前,Query-4才能读取数据。 首先,我们将执行Query-3。

    Query-3:

    查询3:

    BEGIN TRAN;
    UPDATE BankDetailTbl
    SET 
        ClientName='Doris P. Barnum'
    WHERE AccountNumber = '7Y290394';
    WAITFOR DELAY '00:00:50'
    ROLLBACK TRAN
    

    After executing the Query-3, we are executing the Query-4 immediately on another query window at this moment.

    执行完Query-3之后,我们现在正在另一个查询窗口上立即执行Query-4。

    Query-4:

    查询4:

    DECLARE @TimeDiff AS INT
    DECLARE @BegTime AS DATETIME
    DECLARE @EndTime AS DATETIME
    BEGIN TRAN
    SET @BegTime = GETDATE()
    SELECT ClientName FROM BankDetailTbl 
    WHERE AccountNumber = '7Y290394';
    SET @EndTime = GETDATE()
    SET @TimeDiff = DATEDIFF(SECOND,@EndTime,@BegTime)
    SELECT @TimeDiff AS QueryCompletionTime
    COMMIT TRAN
    

    Comparing SQL Server Read Uncommitted vs Read Committed Isolation Level.

    In Query-4, we have measured the query completion time, and the @TimeDiff variable indicates this measured time. As we have seen, Query-4 has completed on 49 seconds because it has waited for the completion of the Query-3 because the Read Committed level does not allow dirty reads. Now we will change this level to Read Uncommitted for Query-4. SET TRANSACTION ISOLATION LEVEL statement helps to explicitly change the isolation level for a transaction. We will execute the Query-3 and Query-4 at the same order and will observe the result.

    在查询4中, 我们 已测量查询完成时间, @ TimeDiff变量指示此测量时间。 正如我们所看到的,Query-4之所以完成了49秒,是因为它等待Query-3的完成,因为Read Committed级别不允许脏读。 现在,我们将把此级别更改为对Query-4的读取未提交SET TRANSACTION ISOLATION LEVEL语句有助于显式更改事务的隔离级别。 我们将以相同的顺序执行Query-3和Query-4,并将观察结果。

    Query-3:

    查询3:

    BEGIN TRAN;
    UPDATE BankDetailTbl
    SET 
        ClientName='Doris P. Barnum'
    WHERE AccountNumber = '7Y290394';
    WAITFOR DELAY '00:00:50'
    ROLLBACK TRAN
    

    Query-4:

    查询4:

    DECLARE @TimeDiff AS INT
    DECLARE @BegTime AS DATETIME
    DECLARE @EndTime AS DATETIME
    BEGIN TRAN
    SET @BegTime = GETDATE()
    SELECT ClientName FROM BankDetailTbl 
    WHERE AccountNumber = '7Y290394';
    SET @EndTime = GETDATE()
    SET @TimeDiff = DATEDIFF(SECOND,@EndTime,@BegTime)
    SELECT @TimeDiff AS QueryCompletionTime
    COMMIT TRAN
    

    Dirty read and isolation levels interaction

    As we can see, the Query-4 did not wait for the completion of the Query-3 and completed as soon as possible.

    如我们所见,Query-4没有等待Query-3的完成,而是尽快完成。

    分配顺序扫描和读取未提交的隔离级别 (Allocation Order Scans and Read Uncommitted Isolation Level)

    In this section, we will discuss an internal secret of the query execution mechanism of the SQL Server. At first, we will execute the following query in the AdventureWorks2017 sample database.

    在本节中,我们将讨论SQL Server查询执行机制的内部秘密。 首先,我们将在AdventureWorks 2017示例数据库中执行以下查询。

    CHECKPOINT;
    DBCC DROPCLEANBUFFERS;
    GO
    BEGIN TRAN
    SELECT WorkOrderID, 
           StartDate, 
           EndDate
    FROM Production.WorkOrder; 
    COMMIT TRAN
    

    These query results are sorted by the WorkOrderId column.

    这些查询结果按WorkOrderId列排序。

    Index order scan example

    Now, we will change the isolation and execute the same query on another query window. However, the result is slightly different than we expected because of the WorkOrderID column sort.

    现在,我们将更改隔离,并在另一个查询窗口上执行相同的查询。 但是,由于WorkOrderID列的排序,结果与我们预期的略有不同。

    CHECKPOINT;
    DBCC DROPCLEANBUFFERS;
    GO
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    BEGIN TRAN
    SELECT WorkOrderID, 
           StartDate, 
           EndDate
    FROM Production.WorkOrder; 
    COMMIT TRAN
    

    Allocation order scan  example

    When we compare the execution plans of these two queries, we could not find any logical difference between them.

    当我们比较这两个查询的执行计划时,我们找不到它们之间的任何逻辑差异。

    SQL Server execution plan compare

    In the execution plan, if we look at the clustered index scan operator Ordered attribute, it shows the “False” value.

    在执行计划中,如果我们查看聚簇索引扫描运算符Ordered属性,它将显示“ False”值。

    Clustered index scan properties

    In this case, the storage engine has two options for accessing the data. The first one is an index order scan that uses the B-tree index structure. The second option is an allocation order scan, and it uses the Index Allocation Map (IAM) and performs the scan in the physical allocation order.

    在这种情况下,存储引擎有两个用于访问数据的选项。 第一个是使用B树索引结构的索引顺序扫描 。 第二个选项是分配顺序扫描,它使用索引分配图(IAM)并按照物理分配顺序执行扫描。

    Allocation order scans can be considered by the database engine when the following reason meets because we don’t care about the data read data consistency.

    当满足以下原因时,数据库引擎可以考虑分配顺序扫描,因为我们不在乎数据读取数据的一致性。

    • The index size is greater than 64 pages

      索引大小大于64页
    • NOLOCK hint NOLOCK提示运行
    • The Ordered attribute of the Index Scan operator is false

      索引扫描运算符的Ordered属性为false

    Tip: Allocation order scans can be performed when we use the TABLOCK hint in a query.

    提示:当我们在查询中使用TABLOCK提示时,可以执行分配顺序扫描。

    CHECKPOINT;
    DBCC DROPCLEANBUFFERS;
    GO
    BEGIN TRAN
    SELECT WorkOrderID, 
           StartDate, 
           EndDate
    FROM Production.WorkOrder  WITH(TABLOCK); 
    COMMIT TRAN
    

    TABLOCK  hint and allocation order scan

    结论 (Conclusion)

    In this article, we discussed the dirty read issue and also explained the Read Uncommitted Isolation Level differences. This level has its own characteristics, so when you decide to use it, we need to take into account lock, data consistency, and other issues. At the same time, we also explored the allocation order scan data access method and details.

    在本文中,我们讨论了脏读问题,并解释了读未提交隔离级别的差异。 此级别具有其自身的特征,因此当您决定使用它时,我们需要考虑锁定,数据一致性和其他问题。 同时,我们还探讨了分配顺序扫描数据的访问方法和细节。

    翻译自: https://www.sqlshack.com/dirty-reads-and-the-read-uncommitted-isolation-level/

    事务隔离级别脏读幻读

    展开全文
  • 1, 脏读一个事务读到另一个事务,尚未提交的修改,就是脏读。这里所谓的修改,除了Update操作,不要忘了,还包括Insert和Delete操作。脏读的后果:如果后一个事务回滚,那么它所做的修改,统统都会被撤销。前一个事务...
  • 这里就有一个问题了:一个事务在写数据的时候,另一个事务要这行数据,该怎么处理?一个事务在写数据,另一个数据也要写这行数据,又该怎么处理这个冲突?其实吧,为了解决这些问题,MySQL 可以说是煞费苦心,使用...
  • 脏读 脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。 如上图所示,t3时刻,事务A读取到了事务B累加5但是还未提交的a值,且在t3时刻,事务B回滚了,那么...
  • 序言脏读、不可重复读、幻读这几个概念开始接触和学习的时候是在大学学习数据库系统的时候,那时候对这几个专业名词的理解停留在概念文字上,并没有真正使用过实践中,最近工作中涉及到这几个概念方面的知识,就来...
  • 这里我依旧是浅谈,脏读很好解释,就是B读取了A还没有提交的事务。 但是为什么会产生脏读?这里就得是事务的隔离性那些,但是我这里不说这个,我从存储方面说说,数据库的数据存在磁盘中,当你读取数据时,这一小...
  • 本章着重点是介绍:出现脏读、幻读、不可重复读的原因,以及设定四种隔离级别如何解决这些现象,结合图例让读者阅读得更加通透 一、什么是事务? 所谓事务是用户定义的一个数据库序列,这些操作要么全做,要么全不...
  • 脏读 准备工作 在讲脏读之前,我们先开启两个会话,并把事务隔离级别更改为读未提交(read uncommitted)。这时,id 为 222 的用户初始年龄为 18。 万事俱备,我们开始吧。 什么是脏读 脏读,就是读到了其他会话还...
  • 脏读 脏读是指一个是事务查询到另一事务还未提交的信息 隔离级别 READ_UNCOMMITTED 例如 (1)事务A执行了一次查询 (2)事务B执行了一次更新语句 (3)事务A再次执行一次查询 此时,事务A查询到的是事务B还未提交的...
  • Mysql有四种事务隔离级别,这四种隔离级别代表当存在多个事务并发冲突时,可能出现的脏读、不可重复读、幻读的问题。 脏读 大家看一下,我们有两个事务,一个是 Transaction A,一个是 Transaction B,在第一个事务...
  • mysql避免脏读

    千次阅读 2021-02-10 23:25:18
    如果我们需要在quantity>0 的情况下才能扣库存,假设程序在第一行SELECT 到的quantity 是2 ,看起来数字没有错,但 是当MySQL 正准备要UPDATE 的时候,可能已经有人把库存扣成0 了,但是程序却浑然不知,将错就错...
  • MySQL数据库的默认隔离级别是REPEATABLE-READ,隔离级别就是数据库为了解决脏读、不可重复读和幻读问题的。 为了能够演示脏读、不可重复读和幻读,我们要先修改数据库的隔离级别,否则无法成功演示。 MySQL...
  • 是不是可以通过乐观锁的问题去解决不可重复读和幻读的问题,MySQL 采用的是 MVCC 机制来解决脏读、不可重复读的问题。MVCC 英文全称是 Muitiversion Concurrency Control,多版本并发控制技术,原理是通过数据行的多...
  • JAVA数据脏读

    2020-12-19 10:28:47
    2014-03-21 回答”数据是指事务t1修改某一数据,并将其写回磁盘,事务t2读取同一数据后,t1由于某种原因被除撤消,而此时t1把已修改过的数据又恢复原值,t2到的数据与数据库的数据不一致,则t2到的数据就...
  • 1、脏读、幻读、不可重复读示例;2、MySQL中的四种事务隔离级别
  • 用sql演示脏读,不可重复读,幻读,不怕你看不懂

    千次阅读 多人点赞 2019-11-22 13:53:13
    脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。 再举一个严重的例子,证明一下危害 表中的数据如下 ...
  • 脏读、不可重复读、幻影读 脏读指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读。 不可重复读...
  • 1、数据库的两种,每种读读的数据版本不一样,所以也称为MVCC,即多版本并发控制a) 快照select * from where xxx 这种形式的都是快照。b) 当前update , insert ,delete ,select xx from xx for update , in ...
  • 快速理解脏读、不可重复读、幻读和MVCC

    千次阅读 多人点赞 2019-06-22 00:00:00
    理解这三种由于并发访问导致的数据读取问题,再理解事务隔离级别就简单多了。脏读(读取未提交数据)A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 130,262
精华内容 52,104
关键字:

脏读

友情链接: freqCompensate.rar