数据库的快照隔离级别(Snapshot Isolation)
SQL Server 并发控制 第三篇:隔离级别和行版本(2)
隔离级别定义事务处理数据读取操作的隔离程度,隔离级别控制读操作的行为。在乐观并发模式下,使用行版本化技术,当对数据进行更新时,都会在tempdb中存储该数据行的原始副本,术语叫作行版本(Row Version),把tempdb中存储行版本的空间叫做版本库。在修改操作发生时,SQL Server 创建一个Row Version,将原始数据复制到版本库,Row Version是在修改操作之前已提交的数据。在数据更新期间,如果有其他读操作要访问该数据,那么它将读取到数据的副本,并且不会阻塞写操作。当写操作完成时,释放行版本。
总结,在乐观并发模式下,使用行版本来保证事务的ACID属性,当读操作引用被其他事务更新,但尚未提交的数据时:
- 对于写操作,对正在更新的数据进行备份,把备份存储到tempdb中。
- 对于读操作,从tempdb中读取行版本,读取在写操作之前存储的副本。
一,启用基于快照的隔离级别
在乐观并发模式下,有两个基于快照的隔离级别,都使用行版本来维护读操作的一致性:
- snapshot 隔离级别,简称SI,实现事务级别的数据一致性,在同一个事务中,读取到的数据是一致的,其行为和SERIALIZABLE隔离级别相同。
- read committed snapshot 隔离级别,简称RCSI,实现语句级别的数据一致性,在同一事务中,可能读取到的数据是不一致的。
1,启用RCSI
在默认的隔离级别Read Committed下,使事务读取Row Versioning数据,只需要把数据库选项READ_COMMITTED_SNAPSHOT设置为ON:
- ALTER DATABASE CURRENT
- SET READ_COMMITTED_SNAPSHOT ON
- WITH NO_WAIT;
当启用READ_COMMITTED_SNAPSHOT选项,意味着把数据库的默认隔离级别设置为RCSI。如果禁用READ_COMMITTED_SNAPSHOT选项,意味着数据库的默认隔离级别是悲观并发模式下的READ COMMITTED隔离级别。
在RCSI隔离级别下,事务有两个特性:
- 事务使用行版本(Row version)代替加锁,读操作不会阻塞其他事务的写操作;
- RCSI隔离级别保证语句级别的事务一致性,查询语句只能读取在该语句执行时已经提交的数据,如果在该语句执行时数据更新尚未提交,该语句读取不到。
2,启用SI
使用快照隔离级别,必须分两步来设置,第一步,设置数据库选项 ALLOW_SNAPSHOT_ISOLATION 为 ON,但是该选项没有改变Session-Level的事务隔离级别,第二步,需要修改Session-Level的事务隔离级别为SNAPSHOT,才能使用行版本数据。
step1,设置数据库选项,允许快照隔离级别
- ALTER DATABASE CURRENT
- SET ALLOW_SNAPSHOT_ISOLATION ON;
step2,把会话的隔离级别设置为SNAPSHOT
把当前Session的隔离级别设置为Snapshot,事务才能访问Row Versioning的数据:
- SET TRANSACTION ISOLATION LEVEL SNAPSHOT
如果不把会话的隔离级别设置为SNAPSHOT,会话的隔离级别是悲观模式下的READ COMMITTED。
二,基于快照的隔离级别
SQL Server 数据库默认的事务隔离级别是Read Committed,会话默认的隔离级别是数据库默认的隔离级别,即是Read Committed。但是会话默认的隔离级别受到数据库选项 READ_COMMITTED_SNAPSHOT 的影响,该选项影响Read Committed 隔离级别是使用行版本控制事务的读操作,还是使用加共享锁来控制事务的读操作。虽然用户不能修改数据库默认的隔离级别,但是用户可以修改会话默认的隔离级别。
在默认的Read Committed隔离级别下,事务不能读取被其他事务修改,但尚未提交的数据,即只能读取已提交更新的数据:
- 设置选项READ_COMMITTED_SNAPSHOT为OFF(默认设置),数据库引擎使用Shared Lock阻止其他事务修改当前事务正在读取的数据;当读取被其他事务修改,但尚未提交更新的数据行时,该读操作将被阻塞。
- 设置选项READ_COMMITTED_SNAPSHOT为ON,数据库引擎使用行版本化(Row Versioning)的数据实现语句级别的一致性,在执行读操作时,事务不会申请共享锁,不会阻塞其他事务的写操作,但只能读取已提交的数据。
1,READ COMMITTED Snapshot隔离级别
READ COMMITTED Snapshot隔离级别(简称RCSI)保证语句级别的读一致性。当数据库选项 READ_COMMITTED_SNAPSHOT 设置为ON,Read Committed隔离级别使用Row Version提供语句级别(Statement-Level)的读一致性,即RCSI隔离级别。
在RCSI下,当一个事务开始运行在RCSI级别下,语句只会看到语句开始时的快照,当重新读取同一个数据时,该数据可能被其他写操作修改,也即是说,在同一个事务中,对同一个数据重复读取,得到的值可能不同。
2,SANPSHOT隔离级别
另外一个基于快照的隔离级别是SANPSHOT隔离级别(简称SI),Snapshot隔离级别使用Row Version 实现事务级别(Transaction-Level)的读一致性。在当前事务开始时,任何读操作,都基于相同的数据snapshot。当读取被其他事务修改的数据行时,读操作只会看到事务开始时的快照,在同一个事务中,对取同一个数据重复读取,得到的值是相同的。
在Snapshot隔离级别下,事务在修改任何数据之前,先将原始数据行复制到tempdb,创建数据行的一个原始版本(Row Version),注意,SQL Server只会复制被修改的数据行,对于未修改的数据行,不会保存行版本数据。后续其他事务的读操作都去读该复制的行版本。在Snapshot隔离级别下,读写操作不会互相阻塞,使用行版本控制能够提高事务的并发性,但是有一个明显的缺点,虽然用户读到的不是脏数据,但是数据可能正在被修改,很快就要过期。如果根据这个过期的数据做数据修改,可能会产生逻辑错误。
3,RCSI和SI的异同
相同点:在snapshot 和 read committed snpshot隔离级别下,事务读取的数据都是已提交的;
不同点:RCSI保证语句级别的读一致性,SI保证事务级别的读一致性:
- 事务级别的读一致性是指:在事务开始,到事务提交期间,该事务持有数据的一个快照。如果在该事务活动期间,其他事务更新表数据,该事务只会读取快照数据,不会读取到被其他事务更新的数据值;
- 语句级别的读一致性是指:单个语句(single statement)看到的数据是一致性的;在当前事务活动期间,事务中的语句能够读取到被其他事务提交更新的数据值;例如,在语句stmt1执行时,事务没有提交更新,stmt1看到Reader1的值是2;当语句stmt2执行时,事务提交更新,stmt2看到Reader2的值是3;
三,引用徐海蔚老师的例子,测试隔离级别的行为
snapshot隔离级别不会阻塞其他事务的写操作,该隔离级别忽略数据的修改操作,只读取row versioning的数据,就是说,读取到的是数据修改之前的版本,当snapshot事务尝试修改由其他事务修改的数据时,产生更新冲突,写操作异常终止。
read committed snapshot隔离级别,读取行版本化的已提交数据:
- 当其他事务未提交更新时,读取行版本化的数据,即读取修改之前的数据值;
- 当其他事务提交数据更新后,读取修改后数据值;
- 由于该隔离级别不会申请共享锁,因此不会阻塞其他事务的更新操作;
- 能够更新由其他事务修改的数据;
四,Snapshot隔离级别
在SNAPSHOT隔离级别下,任何写操作都会将更新之前的数据行保存到tempdb中,读取操作要么从原始数据表中读取数据,要么从tempdb中读取行版本化的数据。Snapshot隔离级别指定:在一个事务中,任何语句读取的数据,是事务一致性的版本。事务一致性是指在事务开始时,在表级别创建数据快照,只能识别其他事务已提交的数据更新。在事务开始之后,当前事务不会识别其他事务执行的数据更新。Sanpshot隔离级别实现事务级别的数据一致性。SQL Server 使用tempdb来存储行版本化(row versioning)的数据,如果数据更新较多,存储的行版本太多,会导致tempdb成为系统瓶颈。
1,在Snapshot隔离级别下,更新操作创建Row Version
一旦启用Snapshot隔离级别,在事务中执行更新操作时,SQL Server将被更新的数据行的原始版本存储在tempdb中,即在tempdb中保存数据行的原始数据,因此,读操作获取取行版本的数据,都是数据被更新之前的值。
2,Snapshot隔离实现事务一致性
Snapshot隔离级别实现事务级别的数据一致性,这意味着,在单个事务中的所有查询语句,看到的是相同版本的数据。在Snapshot隔离级别下,事务在读取数据不需要加行级锁或页级锁,读写操作互不阻塞。
快照隔离级别使得读操作不需要对基础数据行或数据页上施加共享锁,这使其他写事务不会被先前未完成的读事务阻止。修改数据的事务不会阻止读取数据的事务,并且读取数据的事务不会阻止写入数据的事务,这种非阻塞行为显着降低了复杂事务发生死锁的可能性。
3,Snapshot 使用乐观并发模式
Snapshot隔离级别使用乐观并发模式,如果一个Snapshot 事务尝试去提交数据行的更新,但是该数据行已经被其他事务修改,并且修改的时间早于当前事务开始的时间,那么SQL Server将当前事务作为失败者,并回滚其事务操作。乐观并发模式用于冲突较少的环境中,如果应用程序在更新数据时经常发生冲突,Snapshot隔离级别可能不是最好的选择。
参考文档:
Snapshot Isolation in SQL Server
Isolation Levels in the Database Engine
SQL SERVER – Difference Between Read Committed Snapshot and Snapshot Isolation Level
数据库的快照隔离级别(Snapshot Isolation)的更多相关文章
- 转:数据库的快照隔离级别(Snapshot Isolation)
数据库的快照隔离级别(Snapshot Isolation) 隔离级别定义事务处理数据读取操作的隔离程度,在SQL Server中,隔离级别只会影响读操作申请的共享锁(Shared Lock),而 ...
- 数据库ACID、隔离级别与MVCC
首先需要明确事务的概念:一组原子性的SQL查询,如果数据库引擎能够成功的对数据库应用该组查询的全部语句,那么就执行该组语句,否则所有语句都不执行. 事务有ACID四个特性,即: 原子性:一个事务是一个 ...
- MySQL数据库事务各隔离级别加锁情况--read uncommitted篇(转)
本文转自https://m.imooc.com/article/details?article_id=17291,感谢作者 1.目的 1.1 合适人群 1.数据库事务特征我只是背过,并没有很深刻的理解 ...
- MySQL数据库的事物隔离级别
一. 查看数据库的事物隔离级别 mysql> show variables like '%isolation'; +-----------------------+--------------- ...
- 「DB」数据库事务的隔离级别
*博客搬家:初版发布于 2017/04/10 00:37 原博客地址:https://my.oschina.net/sunqinwen/blog/875833 数据库事务的隔离级别 讲事务的隔离 ...
- Mysql数据库事务的隔离级别和锁的实现原理分析
Mysql数据库事务的隔离级别和锁的实现原理分析 找到大神了:http://blog.csdn.net/tangkund3218/article/details/51753243 InnoDB使用MV ...
- Spring中事务的传播行为,7种事务的传播行为,数据库事务的隔离级别
Propagation.REQUIRED 代表当前方法支持当前的事务,且与调用者处于同一事务上下文中,回滚统一回滚(如果当前方法是被其他方法调用的时候,且调用者本身即有事务),如果没有事务,则自己新建 ...
- mysql事务之一:MySQL数据库事务隔离级别(Transaction Isolation Level)及锁的实现原理
一.数据库隔离级别 数据库隔离级别有四种,应用<高性能mysql>一书中的说明: 然后说说修改事务隔离级别的方法: 1.全局修改,修改mysql.ini配置文件,在最后加上 1 #可选参数 ...
- MySQL数据库事务隔离级别(Transaction Isolation Level)
转自: http://www.cnblogs.com/zemliu/archive/2012/06/17/2552301.html 数据库隔离级别有四种,应用<高性能mysql>一书中的 ...
随机推荐
- Javascript 的执行环境(execution context)和作用域(scope)及垃圾回收
执行环境有全局执行环境和函数执行环境之分,每次进入一个新执行环境,都会创建一个搜索变量和函数的作用域链.函数的局部环境不仅有权访问函数作用于中的变量,而且可以访问其外部环境,直到全局环境.全局执行环境 ...
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- C# 中参数验证方式的演变
一般在写方法的时候,第一步就是进行参数验证,这也体现了编码者的细心和缜密,但是在很多时候这个过程很枯燥和乏味,比如在拿到一个API设计文档的时候,通常会规定类型参数是否允许为空,如果是字符可能有长度限 ...
- lua 学习笔记(1)
一.lua函数赋值与函数调用 在lua中函数名也是作为一种变量出现的,即函数和所有其他值一样都是匿名的,当要使用某个函数时,需要将该函数赋值给一个变量,这样在函数块的其他地方就可以通过 ...
- pt-ioprofile
pt-ioprofile是用来观察特定进程的IO信息的. 该脚本是用shell写的,有两方面的作用: pt-ioprofile does two things: ) ) is not performe ...
- jdb调试scala代码的简单介绍
在linux调试C/C++的代码需要通过gdb,调试java代码呢?那就需要用到jdb工具了.关于jdb的用法在网上大家都可以找到相应的文章,但是对scala进行调试的就比较少了.其实调试的大致流程都 ...
- java面向对象六原则一法则
1. 单一职责原则:一类只做它该做的事. 2. 里氏替换原则:子类必须能够替换基类(父类),否则不应当设计为其子类. 3. 依赖倒换原则:设计要依赖于抽象而不是具体化. 4. 接口隔离原则:接口要小而 ...
- linux系统oracle-ora12505问题解决方案一
说明:(1)Linux版本 Linux version 2.6.32.12-0.7-default (geeko@buildhost) (gcc version 4.3.4 [gcc-4_3-bran ...
- Android快乐贪吃蛇游戏实战项目开发教程-05虚拟方向键(四)四个三角形按钮
该系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html 一.如何判断点击的是哪个方向键按钮 在上篇教程中我们实现了左边的三角形按钮效果, ...
- C#编写windows服务,多服务为什么只启动一个(ServiceBase.Run)
https://zhidao.baidu.com/question/380395667.html //多服务一个宿主程序时必须注间以下要点: Service1的ServiceName 必须 Insta ...