我的理解是:

  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. SQL语句中—删除数据

    老大------drop 出没场合:droptable tb --tb表示数据表的名字,下同 绝招:删除内容和定义,释放空间.简单来说就是把整个表去掉.以后要新增数据是不可能的,除非新增一个表 老二- ...

  2. ballerina 学习四 如何进行项目结构规划

    备注: *   ballerina 程序员可以将代码放到一个文件或者一个项目目录 *   一个ballerina program是一个已经编译以及链接的二进制文件 *   package是一个包含ba ...

  3. Let’s Encrypt 将于 2018 年免费提供通配符证书

    旨在让每个网站都启用 HTTPS 加密的 Let's Encrypt CA 宣布将于 2018 年 1 月免费提供通配符证书(Wildcard certificate).通配符证书是一种可被多个子域使 ...

  4. java少包汇总

    1.在下载使用javax.mail的jar包时候,注意: 有的jar没有包含sun的实现,只包含了api,这类jar名称通常为javax.mail-api-x.x.x.jar,在使用smtp协议发邮件 ...

  5. 1.Python3关于文件的操作

    1.写了一个简单的Demo,就是向txt文本写入内容,最初代码如下: file = open("D:/Users/nancy/python.txt","wb") ...

  6. elasticsearch 6.0.0及之后移除了一个索引允许映射多个类型的操作(Removal of mapping types)

    分给线一下内容为理解错误内容,实际允许建立父子分档,只是类型改成来 join 官方demo: join datatypeedit The join datatype is a special fiel ...

  7. SublimeText3搭建go语言开发环境(windows)

    SublimeText3搭建go语言开发环境(windows) 下载并解压:     Sublime Text Build 3021.zip注册:     尽量不要去破解    安装Package C ...

  8. 微服务架构 vs. SOA架构

    面向服务架构(SOA)已经存在有些年头了,这是一种用于设计软件的伟大原则.在SOA中,所有组件都是独立自主的,并能为其他组件提供服务.要替换掉系统中的某些部分而不对整个系统造成较大的影响本是个难题,然 ...

  9. Java堆外内存之一:堆外内存场景介绍(对象池VS堆外内存)

    最近经常有人问我在Java中使用堆外(off heap)内存的好处与用途何在.我想其他面临几样选择的人应该也会对这个答案感兴趣吧. 堆外内存其实并无特别之处.线程栈,应用程序代码,NIO缓存用的都是堆 ...

  10. Vue.js: temple

    ylbtech-Vue.js: temple 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9.返 ...