SQL Server 并发控制 第一篇:并发模式和事务

SQL Server 并发控制 第二篇:隔离级别和锁(1)

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)的更多相关文章

  1. 转:数据库的快照隔离级别(Snapshot Isolation)

    数据库的快照隔离级别(Snapshot Isolation)   隔离级别定义事务处理数据读取操作的隔离程度,在SQL Server中,隔离级别只会影响读操作申请的共享锁(Shared Lock),而 ...

  2. 数据库ACID、隔离级别与MVCC

    首先需要明确事务的概念:一组原子性的SQL查询,如果数据库引擎能够成功的对数据库应用该组查询的全部语句,那么就执行该组语句,否则所有语句都不执行. 事务有ACID四个特性,即: 原子性:一个事务是一个 ...

  3. MySQL数据库事务各隔离级别加锁情况--read uncommitted篇(转)

    本文转自https://m.imooc.com/article/details?article_id=17291,感谢作者 1.目的 1.1 合适人群 1.数据库事务特征我只是背过,并没有很深刻的理解 ...

  4. MySQL数据库的事物隔离级别

    一. 查看数据库的事物隔离级别 mysql> show variables like '%isolation'; +-----------------------+--------------- ...

  5. 「DB」数据库事务的隔离级别

    *博客搬家:初版发布于 2017/04/10 00:37    原博客地址:https://my.oschina.net/sunqinwen/blog/875833 数据库事务的隔离级别 讲事务的隔离 ...

  6. Mysql数据库事务的隔离级别和锁的实现原理分析

    Mysql数据库事务的隔离级别和锁的实现原理分析 找到大神了:http://blog.csdn.net/tangkund3218/article/details/51753243 InnoDB使用MV ...

  7. Spring中事务的传播行为,7种事务的传播行为,数据库事务的隔离级别

    Propagation.REQUIRED 代表当前方法支持当前的事务,且与调用者处于同一事务上下文中,回滚统一回滚(如果当前方法是被其他方法调用的时候,且调用者本身即有事务),如果没有事务,则自己新建 ...

  8. mysql事务之一:MySQL数据库事务隔离级别(Transaction Isolation Level)及锁的实现原理

    一.数据库隔离级别 数据库隔离级别有四种,应用<高性能mysql>一书中的说明: 然后说说修改事务隔离级别的方法: 1.全局修改,修改mysql.ini配置文件,在最后加上 1 #可选参数 ...

  9. MySQL数据库事务隔离级别(Transaction Isolation Level)

    转自: http://www.cnblogs.com/zemliu/archive/2012/06/17/2552301.html  数据库隔离级别有四种,应用<高性能mysql>一书中的 ...

随机推荐

  1. boost强分类器的实现

    boost.cpp文件下: bool CvCascadeBoost::train( const CvFeatureEvaluator* _featureEvaluator, int _numSampl ...

  2. 【流量劫持】躲避 HSTS 的 HTTPS 劫持

    前言 HSTS 的出现,对 HTTPS 劫持带来莫大的挑战. 不过,HSTS 也不是万能的,它只能解决 SSLStrip 这类劫持方式.但仔细想想,SSLStrip 这种算劫持吗? 劫持 vs 钓鱼 ...

  3. 【腾讯bugly干货分享】HTML 5 视频直播一站式扫盲

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=1277 视频直 ...

  4. ExtJS 4.2 业务开发(一)主页搭建

    本篇开始搭建一个ExtJS 4.2单页面应用, 这里先介绍主页的搭建,内容包括:主页结构说明.扩展功能等方面. 目录 1. 主页结构说明 2. 扩展功能 3. 在线演示 1. 主页结构说明 1.1 主 ...

  5. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  6. <译>通过PowerShell工具跨多台服务器执行SQL脚本

    有时候,当我们并没有合适的第三方工具(大部分需要付费)去管理多台数据库服务器,那么如何做最省力.省心呢?!Powershell一个强大的工具,可以很方便帮到我们处理日常的数据库维护工作 .简单的几步搞 ...

  7. [C#] C# 知识回顾 - 特性 Attribute

    C# 知识回顾 - 特性 Attribute [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5911289.html 目录 特性简介 使用特性 特性 ...

  8. Springboot搭建web项目

    最近因为项目需要接触了springboot,然后被其快速零配置的特点惊呆了.关于springboot相关的介绍我就不赘述了,大家自行百度google. 一.pom配置 首先,建立一个maven项目,修 ...

  9. oracle常用函数及示例

    学习oracle也有一段时间了,发现oracle中的函数好多,对于做后台的程序猿来说,大把大把的时间还要学习很多其他的新东西,再把这些函数也都记住是不太现实的,所以总结了一下oracle中的一些常用函 ...

  10. Linux.NET实战手记—自己动手改泥鳅(下)

    在上回合中,我们不痛不痒的把小泥鳅的数据库从只能供在Windows下运行的Access数据库改为支持跨平台的MYSQL数据库,毫无营养的修改,本回合中,我们将把我们修改后得来的项目往Linux中部署. ...