Transaction And Lock--READ COMMITTED隔离级别下的"脏读"

在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隔离级别下的"脏读",布布扣,bubuko.com

时间: 2024-10-08 22:51:04

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

Read Commited 隔离级别下锁情况(MVCC实现原理)

如何通过单纯加锁实现RC隔离级别的隔离效果? 对InnoDB引擎下的mysql数据库支持行级锁,通过对事务访问时增加排他锁(X锁)可以防止其他事务的访问,只有在该事务锁提交也就是commit后才可以访问,避免脏读产生.但是在多读的场景下,一个事务假如在进行update操作,后面有许多请求都想要单纯进行读操作(普通的SELECT语句),可是因为有锁的存在只能进行等待.该方法在多读的并发环境下效率大大降低. 真实情况下由于InnoDB在RC和RR隔离级别下使用了MVCC机制,实现了一致性非阻塞读,提

关于不同隔离级别下锁机制的研究

众所周之,隔离级别分为:       Read Uncommited:可以读取提交的记录      ReadCommitted:仅读到提交的数据,会产生幻读现象     Repeatable Read :对读取到的数据加锁,并对读取的范围加锁,不存在幻读现象     Serializable:读加读锁写加写锁,串行执行   情况一:主键(where  主键=???) Read Committed隔离级别 show create table key_id; +--------+----------

MySQL学习总结-演示不同隔离级别下的并发问题

演示不同隔离级别下的并发问题 1.当把事务的隔离级别设置为read uncommitted,会引发脏读.不可重复读和虚读A窗口set transaction isolation level read uncommitted;start transaction;select * from bank;----发现a账户是1000元,转到b窗口select * from bank; B窗口start transaction;update bank set money=money+100 where n

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

1. innodb在不同隔离级别下的一致性读及锁的差异 不同的隔离级别下,innodb处理sql 时采用的一致性读策略和需要的锁是不同的,同时,数据恢复和复制机制的特点,也对一些sql的一致性读策略和锁策略有很大影响.对于许多sql, 隔离级别越高,innodb给记录集的锁就越严格(龙其是使用范围条件的时候),产生的锁冲突的可能性也就越高,对并发性事务处理性能的影响也就越大.因此,在应用中,应该尽量使用较低的隔离级别,减少锁争用.通常使用Read Commited隔离级别就足够了, 对于一些确实

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

============================================================================== 按照非索引列更新 在可重复读的事务隔离级别下,在非索引列上进行更新和删除会对所有数据行进行加锁,阻止其他会话对边进行任何数据的增删改操作. 如果更新或删除条件为c3=4且c3列上没有索引则: 1.不允许其他会话插入任意记录,因为所有记录的主键索引上存在X排他锁,无法申请插入意向X锁(lock_mode X insert intention

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

原文:浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题 本文出处:http://www.cnblogs.com/wy123/p/7501261.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错误进行修正或补充,无他) 数据库在处理并发事物的过程中,在不同的隔离级别下有不同的锁表现,在非可序列化隔离级别下,存在着脏读,不可重复读,丢失更新,幻读等情况.本文不讨论脏读和不可重复读以及丢失更新的情形,仅讨论幻读,幻

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

事务的概念 事 务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查 询语句因为崩溃或其他原因而无法执行,那么所有的语句就都不会执行.也就是说,事务内的语句要么全部执行,要么一句也不执行. 事务的特性:acid,也称为事务的四个测试(原子性,一致性,隔离性,持久性) automicity:原子性,事务所引起的数据库操作,要么都完成,要么都不执行consisitency:一致性,事务执行前的总和和事务执行后

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

事务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都不会执行.也就是说,事务内的语句要么全部执行,要么一句也不执行. 事务的特性:acid,也称为事务的四个测试(原子性,一致性,隔离性,持久性) automicity:原子性,事务所引起的数据库操作,要么都完成,要么都不执行 consisitency:一致性,事务执行前的总和和事务执行后的总和是不变的

RR隔离级别下锁情况(探究gap锁和行锁)

!!!我的数据库演示版本为5.5,以后会追加最新数据库的演示版本 间隙锁(GAP Lock)时InnoDB在可重复读下的隔离级别下为了解决幻读问题引入的锁机制.幻读存在的问题是因为在新增或者更新时如果进行查询,会出现不一致的现象,这时单纯的使用行锁无法满足我们的需求,我们需要对一定范围的数据加锁,防止幻读. 可重复读隔离级别就是数据库通过行锁和间隙锁(不要搞混gap lock和next-key lock)共同组成来实现的,在网上抄了一下加锁的规则,然后自己进行一下验证: 1.加锁的基本单位是(n