在READ UNCOMMITTED事务隔离级别下或使用WITH(NOLOCK)来查询数据时,会出现脏读情况,因此对于一些比较"关键"的业务,会要求不能使用WITH(NOLOCK)或允许在READ UNCOMMITTED事务隔离级别下,于是我们使用默认的READ COMMITTED隔离级别来访问数据,但是这样真的就没有问题么?

让我们来做个小实验

准备测试数据

--=======================================
--创建测试表
CREATE TABLE TB106
(
C0 INT IDENTITY(1,1) PRIMARY KEY,
C1 INT,
C2 CHAR(100),
C3 NVARCHAR(4000)
) GO
--=======================================
--创建一个非聚簇索引
CREATE INDEX IX_C1_C2
ON TB106(C1,C2)
GO
--=======================================
--向表中填充1000条数据
DECLARE @ID INT
SET @ID=0
WHILE(@ID<1000)
BEGIN
INSERT INTO TB106(C1,C2,C3)
SELECT @ID,@ID,
REPLICATE('A',3800) SET @ID=@ID+1 END
GO
--=================================
--查看表中数据,共1000行
SELECT * FROM TB106

开启回话1,运行以下脚本

--======================
--开启事务,更新C0为100的数据
BEGIN TRAN
UPDATE TB106
SET C1=101
WHERE C0=100

开启回话2,运行以下脚本

--=======================
--查询数据
SELECT C1,C2,C0 FROM TB106

我们会发现回话2被回话1阻塞,但是已经有少量数据开始被读取

我们再次回到回话1,继续执行以下脚本

--=====================
--更新C0为5的数据,并提交事务
UPDATE TB106
SET C1=1000
WHERE C0=5 COMMIT

伴随着回话1事务的提交,回话2没有了阻塞,顺利完成查询,但是奇迹出现了

表中只有1000行数据,为什么我们能查出1001行数据来呢?

我们来分析下执行结果,不难发现c0=5的数据被读取了两遍,更新前后的数据都被读取到,这不科学!在c0=5的数据被更新前,数据被读取了一遍,然后当读到c0=100的时候,回话被阻塞,然后c0=5的数据被更新,更新后的数据记录存放位置变动,移到了索引尾部,当阻塞结束后,该记录又再次被读取,从而导致一行记录被读取两遍。

--=====================================================================

这并不是MS的bug,让我们来仔细阅读下各种隔离级别的解释:

READ UNCOMMITTED 指定语句可以读取已由其他事务修改但尚未提交的行。 在 READ UNCOMMITTED 级别运行的事务,不会发出共享锁来防止其他事务修改当前事务读取的数据。READ UNCOMMITTED 事务也不会被排他锁阻塞,排他锁会禁止当前事务读取其他事务已修改但尚未提交的行。设置此选项之后,可以读取未提交的修改,这种读取称为脏读。在事务结束之前,可以更改数据中的值,行也可以出现在数据集中或从数据集中消失。该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 NOLOCK 相同。这是隔离级别中限制最少的级别。

READ COMMITTED 指定语句不能读取已由其他事务修改但尚未提交的数据。这样可以避免脏读。其他事务可以在当前事务的各个语句之间更改数据,从而产生不可重复读取和幻像数据。该选项是 SQL Server 的默认设置。

REPEATABLE READ 指定语句不能读取已由其他事务修改但尚未提交的行,并且指定,其他任何事务都不能在当前事务完成之前修改由当前事务读取的数据。 对事务中的每个语句所读取的全部数据都设置了共享锁,并且该共享锁一直保持到事务完成为止。这样可以防止其他事务修改当前事务读取的任何行。其他事务可以插入与当前事务所发出语句的搜索条件相匹配的新行。如果当前事务随后重试执行该语句,它会检索新行,从而产生幻读。由于共享锁一直保持到事务结束,而不是在每个语句结束时释放,所以并发级别低于默认的 READ COMMITTED 隔离级别。此选项只在必要时使用。

--=====================================================================

误区:不知道有多少朋友和我一样,错误认为REPEATABLE READ分离级别只是为了保证两次SQL查询的数据不发生变化,而忽略了在一次查询期间内数据发生变化导致的问题。而由于导致该问题的发生概率比较低,往往不能引起我们足够重视,从而错误地认为READ COMMITTED隔离级别可以胜任类似需求。

--======================================================================

依旧是妹子压贴

Transaction And Lock--READ COMMITTED隔离级别下的"脏读"的更多相关文章

  1. Mysql 间隙锁原理,以及Repeatable Read隔离级别下可以防止幻读原理(百度)

    Mysql知识实在太丰富了,前几天百度的面试官问我MySql在Repeatable Read下面是否会有幻读出现,我说按照事务的特性当然会有, 但是面试官却说 Mysql 在Repeatable Re ...

  2. [原创]MySQL RR隔离级别下begin或start transaction开启事务后的可重复读?

    Server version:         5.6.21-log MySQL Community Server (GPL) 前提提要: 我们知道MySQL的RR(repeatable read)隔 ...

  3. mysql 开发进阶篇系列 12 锁问题(隔离级别下锁的差异)

    1. innodb在不同隔离级别下的一致性读及锁的差异 不同的隔离级别下,innodb处理sql 时采用的一致性读策略和需要的锁是不同的,同时,数据恢复和复制机制的特点,也对一些sql的一致性读策略和 ...

  4. MySQL Transaction--RR事务隔离级别下加锁测试

    ============================================================================== 按照非索引列更新 在可重复读的事务隔离级别 ...

  5. MySQL Transaction--RC事务隔离级别下加锁测试

    ==============================================================================非索引列更新 在读提交的事务隔离级别下,在非 ...

  6. mysql中不同事务隔离级别下数据的显示效果--转载

    事务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都 ...

  7. 浅谈mysql中不同事务隔离级别下数据的显示效果

    事务的概念 事 务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查 询语句因为崩溃或其他原因而无法执行,那 ...

  8. 浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题

    本文出处:http://www.cnblogs.com/wy123/p/7501261.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...

  9. Transaction And Lock--快照事务隔离级别

    --================================================--准备数据GOCREATE DATABASE DB5GOUSE DB5GOCREATE TABLE ...

随机推荐

  1. iOS-Xcode必备插件XAlign:瞬间优化你的代码

    今天向大家介绍一个非常好用的Xcode代码编辑插件,这个插件可以很快速地使代码对齐,有3种模式:“=”对齐.宏定义对齐和属性对齐 XAlign效果图 1.“=”对齐   2.宏定义对齐     3.属 ...

  2. java 8 stream特性

    在Java 8的新功能特性中,最棒的特性就是允许我们去表达我们想要完成什么而不是要怎样做.这正是循环的不足之处.要确保循环的灵活性是需要付出代价的.return.break 或者 continue都会 ...

  3. [Android Pro] 跨平台反编译工具 jadx (ubuntu亲测 可用)

    github :  https://github.com/skylot/jadx 输入: .dex, .apk, .jar or .class 输出: 资源文件 和  class文件 不支持重新打包, ...

  4. Android日志监听工具logcat命令详解(转)

    Android日志系统提供了记录和查看系统调试信息的功能.日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过logcat命令来查看和使用. 在使用logcat之前,请确保手机的USB调试 ...

  5. [转]Haproxy 1.5.0 正式发布,Web 负载均衡

    From : http://www.oschina.net/news/53070/haproxy-1-5-0 经过 4 年的不懈努力,HAProxy 1.5.0 终于发布了! 相对于 1.4 版本来说 ...

  6. IIS7增加mine类型,以便可以访问apk

    1.打开IIS 2.找到mine类型,单击右边的添加 3.输入apk的配置 application/vnd.android-package-archive .这样,用户就可以直接访问apk了

  7. lazarus汉化

    启动Lazarus IDE,点击菜单栏中的Environment,再点击Options选项 在弹出的IDE选项框内,点选左侧Environment下的Desktop子选项,将Language设为Chi ...

  8. windows的磁盘操作之四——根据逻辑分区号获得物理磁盘号(转)

    第一节中我们谈到了磁盘设备名称的两种形式: 对于物理驱动器x,形式为\\.\PhysicalDriveX,编号从0开始,例如 名称 含义 \\.\PhysicalDrive0 打开第一个物理驱动器 \ ...

  9. 字符串 CSV解析 表格 逗号分隔值 通讯录 电话簿 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  10. SpringBoot整合Quartz定时任务 的简单实例

    POM.XML文件 <!-- 定时器任务 quartz需要导入的坐标 --> <dependency> <groupId>org.quartz-scheduler& ...