SQL Server 之 事务与隔离级别实例讲解
SQL Server 之 事务与隔离级别实例讲解
SQL Server 实现了6个隔离级别来防止并发情况下,类似企图并发的访问或修改同一数据时问题的发生。本文将带你体验全部6个隔离级别。正如你接下来将看到的,你将理解每个隔离级别所能达成的效果以及何时使用它。
一、事务简介
SQL Server的6个隔离级别中有5个是用于隔离事务的,它们因而被称作事务隔离级别。另外的一个工作于语句级别。
在现实中要求多个数据修改操作必须要么完全成功要么什么也没发生的例子。当数据被合并到数据库时,可能有多个表需要更新。当顾客下订单时,Order表、Invoice Line Item表和Product表的数据可能都需要更新。购买机票也许要求更新Passenger表和Reservations表。无论何时当一个操作要求多个数据更改操作整体地作为单一的单元来处理,这就是需要使用事务的时候。
如果事务中所有的数据更改操作都成功了,那么这些数据更改就可以被提交(也就是持久化到数据库)。否则,截止到失败点事务中所发生的所有数据更改必须被回滚(也就是撤销操作,什么也不曾发生)。
事务相关操作,参照 http://www.cnblogs.com/xinaixia/p/4831198.html 。
二、 隔离级别简介
必须小心对待并发情况,因为它们可能引发已知的并发性问题,包括“脏读”、“不可重复读”和“幻像读”,这些问题可能反过来导致数据的不良后果。正如我们已经知道的,为了防止并发性问题,隔离级别用于将事务或语句相互间隔离开来。
下面是SQL Server 2008中定义的隔离级别名称:
1、Transaction Isolation Level
[1] READ UNCOMMITTED (未提交读,读脏),相当于(NOLOCK)
[2] READ COMMITTED (Default) (已提交读,默认级别)
[3] REPEATABLE READ (可以重复读),相当于(HOLDLOCK)
[4] SERIALIZABLE (可序列化)
[5] SNAPSHOT (快照)
2、Statement Isolation Level
[6] READ COMMITTED SNAPSHOT (已经提交读隔离)
对于前四个隔离级别:READ UNCOMMITTED < READ COMMITTED < REPEATABLE READ < SERIALIZABLE
隔离级别越高,读操作的请求锁定就越严格,锁的持有时间久越长;所以隔离级别越高,一致性就越高,并发性就越低,同时性能也相对影响越大。
获取事务隔离级别(isolation level)
DBCC USEROPTIONS
设置隔离
设置会话隔离
SET TRANSACTION ISOLATION LEVEL <ISOLATION NAME>
--注意:在设置回话隔离时(REPEATABLE READ)两个单词需要用空格间隔开,但是在表隔离中可以粘在一起(REPEATABLEREAD) 设置查询表隔离
SELECT ....FROM <TABLE> WITH (<ISOLATION NAME>)
正如你在下面的例子中即将看到的,隔离级别越高,提供的保护级别也越高(防止更多的并发性问题)。并且,每个隔离级别包括了前一个级别所提供的保护,因此,每个后续的更高隔离级别以避免更多并发性问题的形式提供了额外的保护。但是,世上没有免费的午餐,隔离级别越高,数据可用性就越低。选择合适的隔离级别是一种在高度安全的并发性和数据的高可用性之间寻求平衡的行为。
三、引入实例
为了创建并发环境,所有例子使用2个SQL Server Session,每个会话运行一个不同的事务,每个事务访问相同的资源。在SQL Server Management Studio中,每个查询窗口代表了一个不同的Session,因此,你可以在SQL Server Management Studio中为不同的事务使用不同的查询窗口。
所有例子包含了真实场景以便你将这一切建立在现实的基础上。
1、READ UNCOMMITTED 未提交读
READ UNCOMMITTED 事务隔离级别根本就没有提供事务间的隔离,它允许违反并发性原则的最基本形式之一 -- 脏读。当一个事务能够读取另一个事务中已经Update但尚未Commit的数据时,“脏读”就发生了。READ UNCOMMITTED 读操作不申请锁,运行读取未提交的修改,也就是允许读脏数据,读操作不会影响写操作请求排他锁。
READ UNCOMMITTED 常应用于:单用户系统;系统中两个事务同时访问同一资源的可能性为零或几乎为零;当使用Rowversion数据类型控制并发性时 。
2、READ COMMITTED 已提交读,默认
通过仅允许一个事务读取另一个事务中已经提交的数据,READ COMMITTED 事务隔离级别防止了“脏读”问题。这是SQL Server中默认的事务隔离级别。
它是SQL SERVER默认的隔离级别,可以避免读取未提交的数据,隔离级别比READ UNCOMMITTED未提交读的级别更高;该隔离级别读操作之前首先申请并获得共享锁,允许其他读操作读取该锁定的数据,但是写操作必须等待锁释放,一般读操作读取完就会立刻释放共享锁。
3、REPEATABLE READ 可重复读
正如你在前一个事务隔离级别的步骤2所看到的,Session 2中的事务能够修改已经被Session 1中的事务读取的数据。正像真实场景中所描述的,这可能导致“LOST UPDATE”。REPEATABLE READ 事务隔离级别不允许这种情况发生,因为它违背了REPEATABLE READ原则。换句话说,Session 1中的事务读取同一数据可能会产生不同的结果。
该级别保证在一个事务中的两个读操作之间,其他的事务不能修改当前事务读取的数据,该级别事务获取数据前必须先获得共享锁同时获得的共享锁不立即释放一直保持共享锁至事务完成,所以此隔离级别查询完并提交事务很重要。
4、SERIALIZABLE 可序列化
对于前面的REPEATABLE READ能保证事务可重复读,但是事务只锁定查询第一次运行时获取的数据资源(数据行),而不能锁定查询结果之外的行,就是原本不存在于数据表中的数据。因此在一个事务中当第一个查询和第二个查询过程之间,有其他事务执行插入操作且插入数据满足第一次查询读取过滤的条件时,那么在第二次查询的结果中就会存在这些新插入的数据,使两次查询结果不一致,这种读操作称之为幻读。
为了避免幻读需要将隔离级别设置为 SERIALIZABLE 。为了向你展示SERIALIZABLE 事务隔离级别防止的并发性问题,本例我们从REPEATABLE READ 事务隔离级别开始。
SNAPSHOT 快照分为 SNAPSHOT和READ COMMITTED SNAPSHOT两种隔离(可以把事务已经提交的行的上一版本保存在TEMPDB数据库中):
[1] SNAPSHOT隔离级别在逻辑上与SERIALIZABLE类似;
[2] READ COMMITTED SNAPSHOT隔离级别在逻辑上与 READ COMMITTED类似;
不过在快照隔离级别下读操作不需要申请获得共享锁,所以即便是数据已经存在排他锁也不影响读操作。而且仍然可以得到和SERIALIZABLE与READ COMMITTED隔离级别类似的一致性;如果目前版本与预期的版本不一致,读操作可以从TEMPDB中获取预期的版本。
如果启用任何一种基于快照的隔离级别,DELETE和UPDATE语句在做出修改前都会把行的当前版本复制到TEMPDB中,而INSERT语句不需要在TEMPDB中进行版本控制,因为此时还没有行的旧数据。
无论启用哪种基于快照的隔离级别都会对更新和删除操作产生性能的负面影响,但是有利于提高读操作的性能因为读操作不需要获取共享锁。
5、SNAPSHOT 快照
也许你已经注意到,在上述例1到例4中,防止并发性问题的同时也降低了数据的可访问性。先是不允许Read,然后是不允许Update,不允许Insert。SNAPSHOT事务隔离级别防止了之前那些隔离级别所能防止的许多并发性问题,同时降低了与之相关的成本。它允许更高的数据可用性。
通过在事务开始前在TempDB中使用row versions创建一份数据库的虚拟快照,SNAPSHOT事务隔离级别完成了此壮举。此后它只允许事务访问该数据库虚拟快照。这种方法被称做“基于版本控制的隔离”(versioning-based isolation)。
使用versioning-based isolation,事务仅能看到虚拟快照中的数据。因此,其他事务仍然能够访问同一数据,只要它们不去修改已经被第一个事务修改过的数据就好。如果那样做了(企图修改数据),那么,那些事务将会被回滚并以错误消息终止。
只有当数据库中启用SNAPSHOT事务隔离级别的开关打开后,才能使用它。打开此开关将告知数据库去设置版本化环境。理解这一点很重要,因为,一旦版本化开启,数据库会有维护版本化的开销,无论是否有事务正在使用SNAPSHOT事务隔离级别。
在SNAPSHOT隔离级别下,当读取数据时可以保证操作读取的行是事务开始时可用的最后提交版本。同时SNAPSHOT隔离级别也满足前面的已提交读,可重复读,不幻读;该隔离级别实用的不是共享锁,而是行版本控制,使用SNAPSHOT隔离级别首先需要在数据库级别上设置相关选项。
6、READ COMMITTED SNAPSHOT 提交读快照
到目前为止,所有的隔离级别都是将事务相互间隔离开来。一旦初始事务完成了,对其他事务变得不可用的资源才又变得可用。READ COMMITTED SNAPSHOT 隔离级别在这点上有所不同,它能够读取其已经被他事务提交的数据。它也是通过数据库开关来打开的。然后,任何使用READ COMMITTED SNAPSHOT 隔离级别的事务将通过版本化起作用。
READ COMMITTED SNAPSHOT也是基于行版本控制,但是READ COMMITTED SNAPSHOT的隔离级别是“ 读操作之前的最后已提交版本,而不是事务前的已提交版本 ”,有点类似前面的READ COMMITTED能保证已提交读,但是不能保证可重复读,不能避免幻读,但是又比 READ COMMITTED隔离级别多出了不需要获取共享锁就可以读取数据。
要启用READ COMMITTED SNAPSHOT隔离级别同样需要修改数据库选项。
四、小结
隔离级别 | 解决的并发性问题 | 存在的并发性问题 |
READ UNCOMMITTED | 不适用于并发场合 | Dirty Reads, Non-repeatable Reads, Phantom Reads |
READ COMMITTED | Dirty Reads | Lost Update , Non-repeatable Reads, Phantom Reads |
REPEATABLE READ | Non-repeatable Reads | Phantom Reads, potentially Deadlocking |
SERIALIZABLE | Phantom Reads | Less Data Availability, potentially Deadlocking |
SNAPSHOT | 上述所有并发性问题 | 事务访问的是虚拟快照,其他事务Committed的数据对当前事务仍然不可见,也不允许Update被其他事务Updated的数据。 |
READ COMMITTED SNAPSHOT | 上述所有并发性问题 | 无 |
SQL Server 之 事务与隔离级别实例讲解的更多相关文章
- 转载 SQL Server 2008 R2 事务与隔离级别实例讲解
原文:http://blog.itpub.net/13651903/viewspace-1082730/ 一.事务简介 SQL Server的6个隔离级别中有5个是用于隔离事务的,它们因而被称作事务隔 ...
- SQL Server 事务与隔离级别实例讲解
上班途中,你在一处ATM机前停了下来.正当你在敲入密码的时候,你的一位家人也正在镇上的另一处TAM机上输入密码.你打算从某个还有500元余额的账户上转出400元,而你的家人想从同一账户取走300元.倘 ...
- 查看SQL Server当前会话的隔离级别
查看SQL Server当前会话的隔离级别 DBCC USEROPTIONS
- SQL Server-聚焦事务、隔离级别详解(二十九)
前言 事务一直以来是我最薄弱的环节,也是我打算重新学习SQL Server的出发点,关于SQL Server中事务将分为几节来进行阐述,Always to review the basics. 事务简 ...
- 【转修正】sql server行版本控制的隔离级别
在SQL Server标准的已提交读(READ COMMITTED)隔离级别下,一个读操作会和一个写操作相互阻塞.未提交读(READ UNCOMMITTED)虽然不会有这种阻塞,但是读操作可能会读到脏 ...
- SQL Server 的 6 种隔离级别
背景知识: 高并发一直以来是数据的所追求的目标,然,一般事物是有两面性的.不多说了,等下变邪教了.下面直接看 并发性最高的隔离级别 read uncommitted 1. read uncommitt ...
- 浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题
本文出处:http://www.cnblogs.com/wy123/p/7501261.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...
- SQL Server中的事务与其隔离级别之脏读, 未提交读,不可重复读和幻读
原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中 ...
- SQL Server事务的隔离级别
SQL Server事务的隔离级别 ########## 数据库中数据的一致性 ########## 针对并发事务出现的数据不一致性,提出了4个级别的解决方法: 隔离级别 第一类丢失更新 脏读 ...
随机推荐
- GLSL版本的区别和对比
之前尝试将一个GLSL version 110的版本写成GLSL version 330的,在此将学习过程和收获记录下来. 参考链接 GLSL Versions 介绍 你可以使用#version命令作 ...
- springboot-async
在项目中,当访问其他人的接口较慢或者做耗时任务时,不想程序一直卡在耗时任务上,想程序能够并行执行, 我们可以使用多线程来并行的处理任务,也可以使用spring提供的异步处理方式@Async. Spri ...
- oracle 子查询中null的问题(in 和 not in)
这里的in后面的句子可以理解为or拼接,简单举例即 in (9566,9839,null)可以等价于mgr=9566 or mgr=9839 or mgr=null, not in (9566,983 ...
- 局域网ARP攻击防护
通过借助一些安全软件来实现局域网ARP检测及防御功能. A.电脑管家 电脑管家--工具箱--下载ARP防火墙模块 不支持window2003 B.服务器安全狗 Windows版下载:http://fr ...
- 【译】Apache Kafka支持单集群20万分区
之前网上关于确定Kafka分区数的博客多多少少都源自于饶军大神的文章,如今他带来了这方面的第二篇文章,特此翻译一下,记录一下其中的要点. 原贴地址: https://www.confluent.io/ ...
- 使用 Sublime Text 将含下划线的字符串批量替换为驼峰命名法格式的字符串
本文版权归cxun所有,如有转载请注明出处与本文链接,谢谢!原文地址:http://www.cnblogs.com/cxun/p/7762984.html For indexing: Convert ...
- 查询表DML和DDL操作的最后时间
查询test表DML操作的最后时间的语句: select max(ora_rowscn),to_char(scn_to_timestamp(max(ora_rowscn)),'yyyy-mm-dd h ...
- 【原创】我的KM算法详解
0.二分图 二分图的概念 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V, E)是一个无向图.如果顶点集V可分割为两个互不相交的子集X和Y,并且图中每条边连接的两个顶点一个在X中,另一个在Y ...
- 小程序 将图片文字变成一整张图片海报(判断其中字符串宽度可通过计算字符串.length*字符宽度)
//test.xml<canvas bindtap='showhaibao' canvas-id="myCanvas" style="width:{{canvasw ...
- python--列表,元组,字符串互相转换
列表,元组和字符串python中有三个内建函数:,他们之间的互相转换使用三个函数,str(),tuple()和list(),具体示例如下所示 >>> s = "xxxxx& ...