SQL Server 中的6个事务隔离级别简介

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

数据库中的事物是具有原子性(Atomicity),一致性(Consistemcy),隔离性(Isolation),持久性(Durability)四个特征。
在上述四个特性中的一致性和隔离性的实现中,是通过锁来实现对相同数据的访问隔离的。
事物的隔离级别又可以影响锁的申请和时间的时机。
因此,不同的事物隔离级别又可以对锁的申请和释放产生不同的影响,因此,在对数据库做事物控制的时候需要了解隔离级别对事物的影响。
SQL Server实现SQL99标准规定的事务的四个隔离级别(未提交读,已提交读,可重复读,序列化)之外,另外增加了两个隔离级别(快照个基于行版本的已提交读隔离级别)。
不同的隔离级别对控制脏读,不可重复读,幻读有一定的控制,也会并发有一定程度的影响,
隔离级别越低,并发性越高,但是产生脏读,不可重复读,幻读等可能性越大;随着事物隔离级别的提交,可以控制脏读,不可重复读,以及幻读的现象,但是并发性也会随之降低。
事物隔离级别和执行计划都可以影响锁(范围)的申请和释放时机,本文暂不讨论执行计划对锁申请的影响,仅在隔离级别上说明锁的申请和释放。
以下简单介绍SQL Server中的六个隔离级别以及每个隔离级别的特征,在此基础上说明每个隔离级别可能存在的问题解决方法。

未提交读

运行当前Session读取其他事务已修改但是尚未提交的数据,也即当前Session可以读取到“脏数据”。
当前Session不会对读取的数据加共享锁。
set transaction isolation level read uncommitted;
或者
select * from table with(nolock)

特点:未提交读是最低的一种隔离级别。
存在的问题:脏读,不一致读,幻读等。

如下是未提交度的存在脏读一种演示。

  

已提交读

set transaction isolation level read committed;
或者
select * from table  默认人就是已提交读
运行当前Session不能读取其他事务已修改但是尚未提交的数据。
如果其他事务提对当前Session读取的数据有修改且尚未提交,当前Session被阻塞。
原因是在以已提交读隔离级别情况下:当前Session会对读取的数据加共享锁,如果遇到读取的数据尚未提交,当前查询被阻塞。

特点:相比为提交读隔离级别,解决了未提交读隔离级别下的读取“脏数据”的问题,
存在的问题:存在不可重复度或者幻读的问题。

已提交读隔离级别下存在不可重复读的现象(两次读取的同一行数据结果不一致)

不可重复读隔离级别下存在的幻读现象(一个事物中,同样的条件,读到的数据行数不一致)

  

可重复读

set transaction isolation level repeatable read;
运行当前Session不能读取其他事务已修改但是尚未提交的数据,并且当前Session运行期间,其他Session不能修改当前Session读取到的数据
也就是说,当前Session运行期间,读取到的数据是被加了共享锁的,所加的共享锁一直保持,直到事务提交的时候才释放。
相比已提交读最大的特点就是事务运行期间,共享锁将一直保持,直到当前Session事务提交,
因此可以保持当前Session读取到的数据不被其他Session修改,所以就不存在两次读取的数据不一致的现象。
可重复读隔离级别解决了不可重复读的问题,原因就是在当前Session执行期间,第一次查询的共享锁一直保持到事务结束,
在此期间,其他Session无法修改当前Session读取的数据,因此可以实现可重复读。

特点:相比前一种隔离级别,可重复读解决了已提交读隔离级别的不可重复读的问题,也即两次读取的同一行数据是一致的
存在的问题:相比已提交读,依旧存在幻读的问题。

  如下是可重复读隔离级别的幻读的现象,也即在同一个事物的两次读取期间,其他事物可以写入当前事物读取的数据(范围)

  

可序列化

当前Session不能读取其他Session已修改但未提交的数据(不允许脏读)
当前Session读取的数据上的共享锁一直保持直到事务提交(可重复读)
当前Session事务提交之前,其他Session不能插入当前Session中读取的键值(解决了幻读的问题)
set transaction isolation level serializable
或者开启事务之后对表加holdlock提示
select * from table with(holdlock) where id = n
可序列化解决了另外一个非常经典的问题,使用update table with(holdlock) 或者select * from table with(xlock,holdlock),并发情况下的“存在则更新不存在则插入”重复插入的问题。
参考:http://www.cnblogs.com/TeyGao/p/6929246.html

可序列化锁定的原理是加范围锁的方式来实现的,当一个Session发起了请求之后,对于当前Session范围内的数据,不管是否存在,都加一个共享锁。
比如在可序列化的隔离级别之下,select * from table with where id>=100 and id<= 120
在Session执行期间,SQL Server会锁定 100<=id<= 120这个范围的数据,不管表中这个区间是否存在数据, 都锁定这个Id的范围,不允许该Id范围的数据写入。
也即100<=id<= 120这个范围被所锁定(无法增加删除或者修改这个范围的数据)

可序列化隔离级别解决了幻读的问题,也就是说,当前事物的两次读中间,其他Session对当前Session读取数据范围之内的数据修改的时候,会被阻塞,直到当前事物提交。

  

基于行版本控制的隔离级别

  默认隔离级别,也即已提交读隔离级别下,存在一个明显的问题就是写会阻塞读,也就是说,一个写数据的事物未提交之前,会阻塞其他事物对当前操作数据的读取,直到当前写事物的操作提交。
  基于行版本控制的已提交读隔离级别下,写不会阻塞读,写数据的事物未提交之前,会将修改的数据之前的版本,写入临时数据库,
  读数据的事物在读取的时候,发现要读取的数据被修改,会转向临时库中读取出来一个写事物修改数据之前的版本,这样可以在一定程度上提高并发性(当然临时库会承担一定的压力)。
  SQL Server有两种基于行版本控制的隔离级别:快照隔离级别(snapshot)和基于行版本控制的已提交读隔离级别(read_committed_snapshot)
     两种行版本控制分别要基于数据级别开启allow_snapshot_isolation和read_committed_snapshot

(1)快照隔离级别(snapshot)

数据库级别设置快照隔离级别
alter database Test set allow_snapshot_isolation on;

Session级别设置快照隔离级别:set transaction isolation level snapshot

快照隔离级别最大的特点是,当前Session读取其他事物修改的数据的时候,不会被阻塞,读取的是其他事物已经修改,但是尚未提交的数据
但是当前事物尝试修改“在其他其他事物中提交修改之后的数据”,会报错。
具体过程如下,从时间的维度来看,步骤如下
1)Session2 开启事物,修改Id =1的数据,暂不提交
2)Session1 读取id=1的数据,不会被阻塞,读取到的是Session2修改之前的数据的版本
3)Session2修改Id =1的数据之后,事物提交
4)Session1尝试修改Id=1的数据,报错

  

  实际操作上看,如下

(2)基于行版本控制的已提交读隔离级别(read_committed_snapshot)

数据库级别设置为基于行版本控制的已提交读隔离级
alter database Test set read_committed_snapshot on;
go


--将当前事物设置为已提交读快照隔离级别
set transaction isolation level read committed

快照隔离级别最大的特点是,当前Session读取其他事物修改的数据的时候,不会被阻塞,读取的是其他事物已经修改,但是尚未提交的数据
与快照隔离级别相对,当前Session尝试修改“在其他其他Session中提交修改之后的数据”,可以成功提交。
具体过程如下,从时间的维度来看,步骤如下
1)Session2 开启事物,修改Id =1的数据,暂不提交
2)Session1 读取id=1的数据,不会被阻塞,读取到的是Session2修改之前的数据的版本
3)Session2修改Id =1的数据之后,事物提交
4)Session1尝试修改Id=1的数据,成功提交,

  基于行版本控制的已提交读隔离级别最大的特点是,当前读取的数据是,其他Session已修改尚未提交之前的版本,但是当前事物尝试修改时,可以成功提交
  这样一来,就忽略掉了当前事物运行期间,其他事物修改且提交的那个版本的数据,有点绕,需要慢慢理解。

  行版本控制的已提交读隔离级别的问题也很明显,当前Session读取数据的时候,是其他事物修改之前的版本,当前Session对读取到的数据可以在其他事物提价之前的版本上执行修改,
  而忽略了当前Session在读和写的间隔期间,其他Session修改并且提交事物的影响,为此可能会产生一定程度的影响。

  从时间维度上看如下图所示

具体执行现象如下:
存在的问题就是,Session1第一次读取的时候,读取的Id = 1数据的那么是AAA,实际上此时其他Session2已经将Id = 1的那么修改为了Update_AAA,
随后Session2事物提交,当前Session执行修改的时候,忽略了Session2修改后的数据,可以直接将数据修改为AAA+++
需要注意的是,Session1修改成功的前提是Session2的事物提交,如果Session2修改事物没有提交,Session1的修改操作被阻塞。

截图中第一行的备注没有修改过来,应该是快照已提价读隔离级别

  

  

总结:

  本文简单阐述了SQL Server中的几种隔离级别,SQL Server实现了SQL99定义的四个标准隔离级别,并且额外实现了两个快照隔离级别。
  需要说明的是,不同的DBMS的默认隔离级别和对隔离级别的实现是不完全一样的,也不一定是完全按照SQL99定义的四个标准隔离级别来实现的,
  因此在做事物控制的时候,需要了解具体的隔离级别以及具体特性。

时间: 2024-10-16 18:29:52

SQL Server 中的6个事务隔离级别简介的相关文章

Microsoft SQL Server中的事务与并发详解

本篇索引: 1.事务 2.锁定和阻塞 3.隔离级别 4.死锁 一.事务 1.1 事务的概念 事务是作为单个工作单元而执行的一系列操作,比如查询和修改数据等. 事务是数据库并发控制的基本单位,一条或者一组语句要么全部成功,对数据库中的某些数据成功修改; 要么全部不成功,数据库中的数据还原到这些语句执行之前的样子. 比如网上订火车票,要么你定票成功,余票显示就减一张; 要么你定票失败获取取消订票,余票的数量还是那么多.不允许出现你订票成功了,余票没有减少或者你取消订票了,余票显示却少了一张的这种情况

Microsoft SQL Server中的事务(转载)

1.1 事务的概念 事务是作为单个工作单元而执行的一系列操作,比如查询和修改数据等. 事务是数据库并发控制的基本单位,一条或者一组语句要么全部成功,对数据库中的某些数据成功修改; 要么全部不成功,数据库中的数据还原到这些语句执行之前的样子. 比如网上订火车票,要么你定票成功,余票显示就减一张; 要么你定票失败获取取消订票,余票的数量还是那么多.不允许出现你订票成功了,余票没有减少或者你取消订票了,余票显示却少了一张的这种情况.这种不被允许出现的情况就要求购票和余票减少这两个不同的操作必须放在一起

SQL Server 事务隔离级别

参考文档: https://docs.microsoft.com/zh-cn/sql/t-sql/statements/set-transaction-isolation-level-transact-sql https://msdn.microsoft.com/zh-cn/library/jj856598(v=sql.120).aspx 一.事务隔离级别控制着事务的如下表现: 读取数据时是否占用锁以及所请求的锁类型. 占用读取锁的时间. 引用其他事务修改的行的读操作是否: 在该行上的排他锁被释

事务隔离级别神话与误解

在今天的文章里我想谈下SQL Server里现存的各种事务隔离级别的神话和误解.主要我会谈谈下列话题: 什么是事务隔离级别(Transaction Isolation Levels)? NOLOCK从不阻塞!? 提交读(Read Committed)不会持锁!? Key Range Locks只针对可串行化?! 好,让我们从第1个开始奠定SQL Server里事务隔离级别的基础. 什么是事务隔离级别(Transaction Isolation Levels)? 每次当我站在客户角度,处理各类乱七

SQL Server中锁与事务隔离级别

SQL Server中的锁分为两类: 共享锁 排它锁 锁的兼容性:事务间锁的相互影响称为锁的兼容性. 锁模式 是否可以持有排它锁 是否可以持有共享锁 已持有排它锁 否 否 已持有共享锁 否 是 SQL Server中可以锁定的资源包括:RID或键(行).页.对象(如表).数据库等等. 在试图修改数据(增删改)时,事务会请求数据资源的一个排它锁而不考虑事务的隔离级别.排它锁直到事务结束才会解除.对于单语句事务,语句执行完毕该事物就结束了:对于多语句事务,执行完COMMIT TRAN或者ROLLBA

(转)SQL SERVER的锁机制(三)——概述(锁与事务隔离级别)

五.锁与事务隔离级别 事务隔离级别简单的说,就是当激活事务时,控制事务内因SQL语句产生的锁定需要保留多入,影响范围多大,以防止多人访问时,在事务内发生数据查询的错误.设置事务隔离级别将影响整条连接. SQL Server 数据库引擎支持所有这些隔离级别: · 未提交读(隔离事务的最低级别,只能保证不读取物理上损坏的数据) · 已提交读(数据库引擎的默认级别) · 可重复读 · 可序列化(隔离事务的最高级别,事务之间完全隔离) SQL Server 还支持使用行版本控制的两个事务隔离级别.一个是

SQL点滴9—SQL Server中的事务处理以及SSIS中的内建事务

原文:SQL点滴9-SQL Server中的事务处理以及SSIS中的内建事务 我们可以把SSIS中的整个package包含在一个事务中,但是如果在package的执行过程中有一个表需要锁定应该怎么处理呢?SSIS内建的事务处理可以解决这个问题.在此之前首先来熟悉一下SQL Server中的事务的概念. 事务 SQL Server中的事务是单个的工作单元.如果某一事务成功,则在该事务中进行的所有数据修改均会提交,成为数据库中永久的组成部分.如果事务遇到错误且必须取消或回滚,则所有的数据修改均被清除

十七周-SQL Server中事务日志管理的阶梯,级别5:以完全恢复模式管理日志

SQL Server中事务日志管理的阶梯,级别5:以完全恢复模式管理日志 By Tony Davis, 2012/01/27 http://www.sqlservercentral.com/articles/Stairway+Series/73785/ 该系列 文是SQL Server中"Stairway系列:事务日志管理的阶梯"的一部分 当事情进展顺利时,不需要特别意识到事务日志的作用或工作原理.你只需要确信每个数据库都有正确的备份机制.当事情出错时,对事务日志的理解对于采取纠正措施

事务隔离级别中可重复读与幻读

前言 中秋刚过,大家是不是还没充中秋的假日里缓过来?三天假期里,我深入窥探了Innodb中可重复读与幻读,非常有意思,分享给大家,作为大家工作前的开胃小菜,希望有所帮助. 每次谈到数据库的事务隔离级别,大家一定会看到这张表. 其中,可重复读这个隔离级别,有效地防止了脏读和不可重复读,但仍然可能发生幻读,可能发生幻读就表示可重复读这个隔离级别防不住幻读吗? 我不管从数据库方面的教科书还是一些网络教程上,经常看到RR级别是可以重复读的,但是无法解决幻读,只有可串行化(Serializable)才能解