我的理解是:

  step1,假设表里有100行有序记录, 事务1从row 1 开始读取到了row 50 并准备继续读取完这100行。

  要注意的是,sql server 会自动释放已经读取了的row的锁。

  step2,这时候,另外一个事务2 修改了 事务1已经读取并且被 sql server 释放掉锁的前面50行中的某些数据。

  这修改操作导致了数据排序发生变化,可能原来已经读取了的第20行现在排到了50行后面去。

  step3,然后,事务1继续读取剩下的数据。 就可能发现有数据被重复读取出来了。

demo如下:

  1. 建立表和填充数据。

CREATE TABLE dbo.testDoubleRead
(
id int identity(10,1) PRIMARY KEY,
text_asc nvarchar(20)
)
go CREATE NONCLUSTERED INDEX IX_testDoubleRead_text_asc ON dbo.testDoubleRead(text_asc ASC); INSERT INTO dbo.testDoubleRead (text_asc)
VALUES('A'),('B'),('C'),('D')

注意非聚集索引的排序是 ASC,这时候表里的数据是:

SELECT * FROM dbo.testDoubleRead

/*

id    text_asc
10 A
11 B
12 C
13 D */

  2. 开一个新session,执行下面这段不完整的事务:

--SESSION 1 SCRIPT
BEGIN TRANSACTION UPDATE dbo.testDoubleRead
SET text_asc = 'UPDATE_C'
WHERE id = 12

  3. 开另外一个session, 执行下面的查询:

SELECT * FROM dbo.testDoubleRead

  显然,这查询是会被session1 block住的。

  

  4. 回到session1, 执行完毕如下代码:

UPDATE dbo.testDoubleRead
SET text_asc = 'UPDATE_B_2'
WHERE id = 11 COMMIT TRANSACTION

  5. 这时候, session2 会查询完毕,结果如下:

SELECT * FROM dbo.testDoubleRead

/*
id text_asc
10 A
11 B
13 D
11 UPDATE_B_2
12 UPDATE_C
*/

  可以看到,有两条 id = 11的记录!

再次分析下:

  1。按照 非聚集索引的定义,刚开始的数据应该是这样的

/*
id text_asc
10 A
11 B
12 C
13 D
*/

  2. session1 开启事务并修改了id=12 的行,但没有提交。 这时候,session2 尝试读取数据 但只能读取到 id=11的,不能再朝下读取了;除非session1 释放id=12 的行。

  3. 接上面,session1 把id=12 的行修改了,根据非聚集索引的排序规则 text_asc ASC,可以确定值‘UPDATE_C’是应该排到最后一行的。 而且id=11的新值‘UPDATE_B’是在倒数第二行。

  理想数据的样子应该是这样的:

/*
id text_asc
10 A
13 D
11 UPDATE_B_2
12 UPDATE_C
*/

  

  4.session修改完id=11以后就提交,这样session2就可以继续之前的查询了。注意的是,session2在被block之前已经读取了:  (id=11,text_asc='B')

  5.综合上面的几点,session2继续按照非聚集索引的顺序读取(id=13开始),而不会清空之前已经读取完毕的(id=11,text_asc='B')。

  所以最终的结果就是这样的了:

/*
id text_asc
10 A
11 B --在被session1的修改事务block之前读取了这行
13 D --session1提交事务以后,session2从这行继续读
11 UPDATE_B_2
12 UPDATE_C
*/

  

T-SQL 重复读(Double Read)问题的理解的更多相关文章

  1. mysql系列:加深对脏读、脏写、可重复读、幻读的理解

    关于相关术语的专业解释,请自行百度了解,本文皆本人自己结合参考书和自己的理解所做的阐述,如有不严谨之处,还请多多指教. 事务有四种基本特性,叫ACID,它们分别是: Atomicity-原子性,Con ...

  2. [MySQL]对于事务并发处理带来的问题,脏读、不可重复读、幻读的理解

    一.缘由 众所周知MySQL从5.5.8开始,Innodb就是默认的存储引擎,Innodb最大的特点是:支持事务.支持行级锁. 既然支持事务,那么就会有处理并发事务带来的问题:更新丢失.脏读.不可重复 ...

  3. SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因

    原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中 ...

  4. MySQL Transaction--MySQL与SQL Server在可重复读事务隔离级别上的差异

    MySQL和SQL Server两种数据库在REPEATABLE-READ事务隔离级别实现方式不同,导致使用上也存在差异. 在MySQL中,默认使用REPEATABLE-READ事务隔离级别,MySQ ...

  5. SQL Server中的事务与其隔离级别之脏读, 未提交读,不可重复读和幻读

    原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中 ...

  6. 如何理解SQL的可重复读和幻读之间的区别?

    从本源来理解比较容易理解,如果只是描述概念和定义,容易让人云里雾里找不到方向.正好这两天在浏览mysql的文档,我可以简单在这里总结一下,帮助其他还没有理解的朋友,如果有错误也麻烦帮忙指正. 先讲一点 ...

  7. Sql server脏读、更新丢失、不可重复读、幻象读问题及解决方案

    1.脏读:一个事务读到另外一个事务还没有提交的数据.解决方法:把事务隔离级别调整到READ COMMITTED,即SET TRAN ISOLATION LEVEL READ COMMITTED.这时我 ...

  8. MySQL进阶15--TCL事务控制语言--建立结束事务/设置断点--默认隔离级别--脏读/幻读/不可重复读

    #TCL事物控制语言 : /* Transaction control language : 事物控制语言 事务: 一个或者一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行; ...

  9. MySQL(25):事务的隔离级别出现问题之 不可重复读

    1. 不可重复读 所谓的不可重复读(Non-Repeatable Read)是指事务中两次查询的结果不一致,原因是在查询的过程中其他事务做了更新的操作. 例如,银行在做统计报表的时候,第一次查询a账户 ...

  10. MySQL选用可重复读之前一定要想到的事情

    原文地址:http://blog.itpub.net/29254281/viewspace-1398273/ MySQL选用可重复读隔离级别之前一定要想到的事情.间隙锁 MySQL在使用之前有三个务必 ...

随机推荐

  1. BestCoder Round #1 第一题 逃生

    // 等了好久,BESTCODER 终于出来了..像咋这样的毕业的人..就是去凑凑热闹// 弱校搞acm真是难,不过还是怪自己不够努力// 第一题是明显的拓扑排序,加了了个字典序限制而已// 用优先队 ...

  2. 《DSP using MATLAB》示例Example 8.3

  3. 淘宝npm镜像使用

    淘宝NPM镜像使用 镜像使用方法 1.config命令 npm config set registry https://registry.npm.taobao.org npm info undersc ...

  4. 控制已经打开的Excel

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  5. pycharm中import动态链接库pyd有错误

    有红色波浪线提示unsolved reference云云 去setting里面设置interpreters,  在path里面添加对应的路径, 是包含对应头文件的路径, 不要忘记右边的小按钮去Relo ...

  6. Nchan 实时消息内置变量

      以下参考官方文档:   $nchan_channel_idThe channel id extracted from a publisher or subscriber location requ ...

  7. 【转】简述configure、pkg-config、pkg_config_path三者的关系

    原文网址:http://www.mike.org.cn/articles/description-configure-pkg-config-pkg_config_path-of-the-relatio ...

  8. 搭建基于hyperledger fabric的联盟社区(五) --启动Fabric网络

    现在所有的文件都已经准备完毕,我们可以启动fabric网络了. 一.启动orderer节点 在orderer服务器上运行: cd ~/go/src/github.com/hyperledger/fab ...

  9. java代码----I/O流从控制台输入信息判断并抛出异常

    package com.a.b; import java.io.*; public class Yu { public static void main(String[] args) throws I ...

  10. Java GC日志查看

    Java GC类型 Java中的GC有哪几种类型? 参数 描述 UseSerialGC 虚拟机运行在Client模式的默认值,打开此开关参数后, 使用Serial+Serial Old收集器组合进行垃 ...