MSSQL-并发控制-2-Isolation
MySQL通过MVCC和锁来实现并发控制,在4个隔离级别中,读写数据方式及加锁方式有所不同,以满足不同的业务需求。
1 并发控制理论
1.1 悲观并发控制
1.2 乐观并发控制
2 隔离级别
2.1 隔离级别说明
- Read UnCommitted
- 简称 RU,读未提交记录,始终是读最新记录
- 可能存在脏读、不可重复读、幻读等问题
- 读的过程不加S锁,等同于 SELECT * FROM tbname with(nolock)
- Read Committed
- 简称 RC ,读已提交记录
- 可能存在不可重复读、幻读等问题
- 读的过程加 S锁,无论事务是否结束,SELECT 语句一旦结束,立马释放S锁,不会等到事务结束才释放锁,遵循的是 Strict 2-PL
- Read Commmitted (行版本)
- 简称 RCSI
- 应用MVCC原理,版本读,读已提交记录,但是读取到的不一定是最新的记录
- 同个事务中,读取数据都是同一个版本
- 不存在脏读、不可重复读问题,可能存在幻读问题
- 行版本控制隔离级别 中的版本数据,不存在与数据库本身,而是存在 tempdb ,下文会详细描述这一隔离级别
- Read Repeattable
- 简称 RR ,可重复读记录
- 可能存在幻读等问题
- 读的过程加S锁,直到事务结束,才释放S锁,遵循的是 Stong Strict 2-PL
- Snapshot
- 简称 SI
- 下文会详细描述这一隔离级别
- Read Serializeble
- 简称 RS,序列化读记录
- 不存在 脏读、不可重复读、幻读等问题
- 读的过程中除了添加S锁,还添加范围锁;修改数据的过程中,除了添加 X 锁,也会添加范围锁,避免在符合条件的数据在操作过程中,有其他符合条件的数据INSERT进来
- 并发度最差,除非明确业务需求及性能影响才使用,曾经遇到过某个短信业务的框架默认使用这个隔离级别,上线后爆发死锁上K个,马上分析紧急修复....
2.2 Read Commmitted Snapshot Isolation 与 Snapshot Isolation
- 同个事务,多次 SELECT * FROM tbname WHERE id=2
- RCSI,在同个事务中,每个SQL启动的时候,提交数据到tempdb表格(个人推测,应该是会分配一个类似hash字符串之类的,如果同个事务中的多次查询结果一致,应该不用在每个SQL开始的时候,重复提交行版本到tempdb),从tempdb中读取最新版本信息,如果tempdb没有版本信息,则从 数据库中读取,并把读取到的记录存储在 tempdb。会存在同个事务中,多次读取数据结果不一致的情况。
- SI,在同个事务中,同个事务内的相同SQL 从tempdb中读取距离当前事务最新的版本,整个事务内部的SQL都是用这个版本数据,如果tempdb没有版本信息,则从 数据库中读取,并把读取到的记录存储在 tempdb。同个事务中,不会存在 多次读取数据结果不一致的情况。
- UPDATE tbname SET colname='xinysu' WHERE id=18
- RCSI,直接读取数据库中的数据,根据主键加上X锁,更新数据,这个操作跟 RC 隔离级别是一样的。
- SI,读取 行版本 数据,在行版本上选择需要更新的行,修改成功后把数据 修改到实际的数据库中去,如果 实际数据库中的数据在这段操作期间已被其他事务修改了数值,则会出现更新冲突,该事务将报错停止。即,SI 在 UPDATE 的时候,有更新冲突检测。
- 为啥要先在行版本上更新,最后在更新到实际数据上?
- 假设一个UPDATE运行需要3s,但是只更新了1条行记录,如果直接在实际数据上更新,则需要锁定扫描记录3s,最后更新,中间会堵塞到其他事务对该数据的查询,但是如果在行版本上更新,则不需要锁住 实际数据,最后更新1行记录的时候,非常快,避免长时间的堵塞,提高并发能力。
属性
|
使用行版本控制的已提交读隔离级别
|
快照隔离级别
|
数据库级选项启动
|
READ_COMMITTED_SNAPSHOT
|
ALLOW_SNAPSHOT_ISOLATION
|
事务设置
|
使用默认的已提交读隔离级别,或运行 SET TRANSACTION ISOLATION LEVEL 语句来指定 READ COMMITTED 隔离级别
|
SET TRANSACTION ISOLATION LEVEL 来在事务启动前指定 SNAPSHOT 隔离级别
|
行版本处理
|
在每条语句启动前提交的所有数据。
|
在每个事务启动前提交的所有数据。
|
更新处理
|
从行版本恢复到实际的数据,以选择要更新的行并使用选择的数据行上的更新锁。 获取要修改的实际数据行上的排他锁。 没有更新冲突检测。
|
使用行版本选择要更新的行。 尝试获取要修改的实际数据行上的排他锁,如果数据已被其他事务修改,则出现更新冲突,同时快照事务也将终止。
|
更新冲突检测
|
无
|
集成支持。 无法禁用。
|
3 隔离级别测试
- RU,事务开始的时候,设置 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
- RC,事务开始的时候,设置 SET TRANSACTION ISOLATION LEVEL READ COMMITTED
- RCSI,整个数据库级设置 READ_COMMITTED_SNAPSHOT 为ON,注意,设置的这个的时候需要获取数据库的独占权,也就是当前不允许有用户线程连接数据库,否者这个设置SQL会一直处于堵塞情况。如果当前数据库的默认隔离级别是 RC,则设置后,默认为RCSI,否者,需要在事务开始的时候,设置 SET TRANSACTION ISOLATION LEVEL READ COMMITTED
- 数据库设置:当前数据库下,执行 ALTER DATABASE dbname SET READ_COMMITTED_SNAPSHOT ON
- 事务设置:SET TRANSACTION ISOLATION LEVEL READ COMMITTED
- RR,事务开始的时候,设置 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
- RS,事务开始的时候,设置 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
- SI,整个数据库级设置 ALLOW_SNAPSHOT_ISOLATION 为ON,同时设置事务的隔离级别为 SNAPSHOT。注意,这里的 ALLOW_SNAPSHOT_ISOLATION 设置也是需要获取数据的独占锁。
- 数据库设置:当前数据库下,执行 ALTER DATABASE dbname SET ALLOW_SNAPSHOT_ISOLATION ON
- 事务设置:SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
CREATE TABLE tb_no_index ( id int primary key not null identity(1,1), age int not null, name varchar(100) );
CREATE TABLE tb_index ( id int primary key not null identity(1,1), age int not null, name varchar(100) );
CREATE TABLE tb_unique_index ( id int primary key not null identity(1,1), age int not null,name varchar(100) );
CREATE INDEX IX_age ON tb_index(age)
CREATE INDEX IX_unique_age ON tb_index(age)
INSERT INTO tb_no_index(age) values(2),(9),(21),(4),(7),(25);
INSERT INTO tb_index(age) values(2),(9),(21),(4),(7),(25);
INSERT INTO tb_unique_index(age) values(2),(9),(21),(4),(7),(25);
3.1 Read Uncommitted
- 数据不一致情况测试截图
- RU测试结论
- 在RU隔离级别下
- 不会出现更新丢失情况(锁机制),但是会出现 脏读、不可重复读及幻读的情况。
- 读不加行锁,可以读未提交数据
3.2 Read Committed
- 数据不一致情况测试截图
- 读情况测试
- RC测试结论
- 在RC隔离级别下
- 不会出现更新丢失情况(锁机制)、脏读现象,但是会出现 不可重复读及幻读的情况
- 读需要申请锁,故不会出现脏读情况
- 遵循 强2-PL模式,事务内的读锁读完即刻释放,写锁等到事务提交的时候才释放。
3.3 Read Commit Snapshot Isolation
- 测试环境设置
- 实现设置数据库隔离级别为:
- 检查当前会话的默认隔离级别:
- 数据不一致情况测试截图
- 更新冲突测试
- RCSI 测试结论
- 读不加锁,但申请表格的架构锁,读行版本数据
- 不存在丢失更新、脏读情况,但是存在不可重复读及幻读情况
- 没有更新冲突检测,RCSI跟RC的更新处理方式一样
3.4 Read Reaptable
- 数据不一致情况测试截图
- RR测试结论
- 读加S锁,事务结束后才释放S锁
- 不存在丢失更新、脏读及不可重复读情况,但是存在幻读情况
3.5 Read Serializable
- 数据不一致情况测试截图
- RS 测试结论
- 读加S锁,事务结束后才释放S锁
- 增加了范围锁
- 不存在丢失更新、脏读、不可重复读、幻读情况
- 并发能力最差
3.6 Snapshot Isolation
- 数据不一致情况测试截图
- 更新冲突测试
- SI 测试结论
- 不存在 丢失更新、脏读、幻读等数据不一致情况
- 读不加锁,为读行版本数据
- 具有冲突监测,无法禁用,如果使用这个隔离级别,程序要做更新冲突的回滚处理
4 总结
隔离级别
|
说明
|
脏读
|
不可重复读
|
幻影
|
并发控制模型
|
Read UnCommitted
|
未提交读
|
YES
|
YES
|
YES
|
悲观
|
Read Committed
|
已提交读
|
NO
|
YES
|
YES
|
悲观
|
Read Commmitted (行版本)
|
已提交读(快照)
|
NO
|
YES
|
YES
|
乐观
|
Read Repeattable
|
可重复读
|
NO
|
NO
|
YES
|
悲观
|
Snapshot
|
快照
|
NO
|
NO
|
NO
|
乐观
|
Read Serializeble
|
可串行化
|
NO
|
NO
|
NO
|
悲观
|
MSSQL-并发控制-2-Isolation的更多相关文章
- MSSQL-并发控制-1-Transaction
MSSQL并发控制原先打算分为两个部分写:隔离级别及锁,写的过程中,发现需要提及下事务的相关内容,故加多一篇博文,共3篇. 如果转载,请注明博文来源: www.cnblogs ...
- mysql innodb事务的ACID及其实现的保证机制
MySQL事务的ACID,一致性是最终目的.保证一致性的措施有:A原子性:靠undo log来保证(异常或执行失败后进行回滚).D持久性:靠redo log来保证(保证当MySQL宕机或停电后,可以通 ...
- 并发控制MsSql
Isolation 阅读目录(Content) 1 并发控制理论 1.1 悲观并发控制 1.2 乐观并发控制 2 隔离级别 2.1 隔离级别说明 2.2 Read Commmitted Snaps ...
- MSSQL事务隔离级别详解(SET TRANSACTION ISOLATION LEVEL)
控制到 Transact-SQL 的连接发出的 SQL Server 语句的锁定行为和行版本控制行为. TRANSACT-SQL 语法约定 语法 -- Syntax for SQL Server ...
- 浅谈MS-SQL锁机制
锁的概述 一. 为什么要引入锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 丢失更新A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订票系统 脏 ...
- 数据库的快照隔离级别(Snapshot Isolation)
隔离级别定义事务处理数据读取操作的隔离程度,在SQL Server中,隔离级别只会影响读操作申请的共享锁(Shared Lock),而不会影响写操作申请的互斥锁(Exclusive Lock),隔离级 ...
- MVCC PostgreSQL实现事务和多版本并发控制的精华
原创文章,同步发自作者个人博客,http://www.jasongj.com/sql/mvcc/ PostgreSQL针对ACID的实现机制 事务的实现原理可以解读为RDBMS采取何种技术确保事务的A ...
- mysql事务和并发控制
谈到事务,首先想到的问题是并发控制.比如两个用户同时操作数据库里面的一张表,一个正在读数据,一个正在删除数据,那么读数据的读出的结果究竟是多少?并发可以提高系统的性能,让多个用户同时操作一份数据,但为 ...
- 第17/24周 悲观并发控制(Pessimistic Concurrency)
大家好,欢迎回到性能调优培训.今天标志着第5个月培训的开始,这个月我们会谈论SQL Server里的锁.阻塞和死锁(Locking, Blocking, and Deadlocking). SQL S ...
- 第18/24周 乐观并发控制(Optimistic Concurrency)
大家好,欢迎回到性能调优培训.上个星期我通过讨论悲观并发模式拉开了第5个月培训的序幕.今天我们继续,讨论下乐观并发模式(Optimistic Concurrency). 行版本(Row Version ...
随机推荐
- 简单说下C#变量的作用域
变量的作用域分为局部变量和全局变量举个小例子 class Program { int i = 3;//这个变量i 需要实例化Program才能使用 static void Main(string[] ...
- windows server git
我有一个阿里云,windows server,我想把代码放阿里云 我去做git,只需要安装copssh 下载git https://git-for-windows.github.io/ 下载Copss ...
- 浅谈 var 关键字
提起 var关键子,程序员的第一反应就是JavaScript, 事实上这个关键子在其他语言中也有被采用. 比如说C#, 比如说kotlin, 用法和JavaScript中使用差不多,作为要声明变量的前 ...
- 对ajax请求的简单封装,操作更方便
我这里的接口数据调用的js叫interface.js,接口路径管理的js叫webSiteControl.js /** * Created by l2776 on 2017/7/11. * 接口数据调用 ...
- session和cookie作用原理,区别
Cookie概念 在浏览某些 网站 时,这些网站会把 一些数据存在 客户端 , 用于使用网站 等跟踪用户,实现用户自定义 功能. 是否设置过期时间: 如果不设置 过期时间,则表示这个 Cookie生命 ...
- java字串加密
字串加密 1.设计思想: (1)加密方法,字符串的每一个字符都代表这个字符往后的第三位,最后三个字符代表,开始的三个字符. (2)解密方法,字符串的每一个字符都代表这个字符往前的第三位,开始三个字符代 ...
- 树莓派.安装Samba环境
适用于树莓派3 树莓派装好系统后, 为了方便传文件到树莓派, 建议使用Samba这类文件夹级别的应用, 比ftp方便多了 如果你想把树莓派变成Nas, Samba也是不可或缺的应用 通过samba服务 ...
- Linux.杀毒.Centos安装杀毒软件Clam
Linux系统用了几年, 甚少中毒 但前不久在阿里云的服务器被种马,折腾了几周才解决干净 感觉还是装个杀毒/马软件定期扫一扫比较稳妥, 这个Clam是免费的, 安装和配置办法记录如下: 已验证适用环境 ...
- java笔记3(动手动脑)
1.以下代码为何无法通过编译?哪儿出错了? 原因:已有的Foo()是带一个int型参数的构造方法,不存在无参的构造方法Foo() "构造方法" 当创建一个对象时,它的构造方法会被自 ...
- PHP Curl模拟登录并抓取数据
使用PHP的Curl扩展库可以模拟实现登录,并抓取一些需要用户账号登录以后才能查看的数据.具体实现的流程如下(个人总结): 1. 首先需要对相应的登录页面的html源代码进行分析,获得一些必要的信息: ...