【SqlServer系列】浅谈SQL Server事务与锁(上篇)
一 概述
在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章试图采用图文的方式来与大家一起探讨。
“浅谈SQL Server 事务与锁”这个专题共分两篇,上篇主讲事务及事务一致性问题,并简略的提及一下锁的种类和锁的控制级别。
下篇主讲SQL Server中的锁机制,锁控制级别和死锁的若干问题。
二 事务
1 何为事务
预览众多书籍,对于事务的定义,不同文献不同作者对其虽有细微差别却大致统一,我们将其抽象概括为:
事务:指封装且执行单个或多个操作的单个工作单元,在SqlServer中,其定义表现为显示定义和隐式定义两种方式。
基于如上的定义,我们可以将事务解剖拆分为如下几个点:
(1)事务是单个工作单元,这一定义,才使事务具有ACID属性
(2)事务是封装操作的,如封装基本的CRUD操作
--事务
Begin Tran
SELECT * FROM UserInfo
INSERT INTO UserInfo VALUES('Alan_beijing',35)
UPDATE UserInfo SET Age=31 WHERE UserName='Alan_beijing'
DELETE UserInfo WHERE UserName='Alan_beijing'
Commit Tran
(3)事务在封装操作时,可以封装单个操作,也可以封装多个操作(封装多个操作时,应注意与批处理的区别)
(4)在SqlServer中,事务的定义分为显示定义和隐式定义两种方式
显示定义:以Begin Tran作为开始,其中提交事务为Commit Tran,回滚事务为RollBack Tran,如我们在一个事务中插入两条操作语句
--显示定义事务
Begin Tran
INSERT INTO UserInfo VALUES('Alan_shanghai',30)
INSERT INTO UserInfo VALUES('Alan_beijing',35)
Commit Tran
隐式定义:如果不显示定义事务,SQL Server 默认把每个语句当作一个事务来处理(执行完每个语句之后就自动提交事务)
2 事务的ACID属性
事务作为单个工作单元,该定义使其具有ACID属性,ACID属性指原子性(Atomicity)、一致性(Consisitency)、隔离性(Isolation)和持久性(Durability)。
(1)原子性(Atomicity)
原子性指事务必须是原子工作单元,即对于事务的封装操作,要么全部执行,要么全都不执行。如下情况均会导致事务的撤销或回滚。。。
a.事务提交之前,系统发生故障或重新启动,SQL Server将会撤销在事务中进行的所有操作;
b.事务处理中遇到错误,SQL Server通常会自动回滚事务,但也有少数例外;
c.一些不太严重的错误不会引发事务的自动回滚,如主键冲突,锁超时等;
d.可以使用错误处理代码来捕获一些错误,并采取相应的操作,如把错误记录在日志中,再回滚事务等;
(2)一致性(Consisitency)
一致性主要指数据一致性,即主要对象是数据。从宏观上来说,指某一段时间区间,数据要保持一致性状态,从微观上来说,某个时间点数据要保持一致性状态,我们举个例子,
假若有两个事务A和B对同一张表进行操作,A向表中写数据,B向数据表中读取数据,可以猜测,B读取的数据大致有三种粗粒度可能:
第一种可能:A还没向数据表中写入数据的状态;
第二种可能:A已向数据表中写入部分数据,但还未写完的状态;
第三种可能:A已向数据表中写完数据;
如此,造成了事务的不一致性。
关于事务一致性,可能会发生 丢失更新,脏读,不可重复读和幻读等问题,下文会详细论述这些事务一致性问题。
(3)隔离性(Isolation)
隔离性指当两个及其以上事务对同一边界资源进行操作时,要控制好每个事务的边界,控制好数据访问机制,确保事务只能访问处于期望的一致性级别下的数据。
在SQL Server中,一般采用锁机制来控制,下文中,我们会详细论述。
(4)持久性(Durability)
我们对数据表进行操作时,一般会按照先后顺序执行如下两步:
第一步:将对数据表操作写入到磁盘上数据库的事务日志中(持久还到磁盘事务日志中);
第二步:完成第一步后,再将对数据表操作写入到磁盘上数据库的数据分区中(持久化到磁盘上数据库分区中);
关于如上两步,我们来想想可能发生的问题:
问题1:完成如上第一步之前,系统发生故障(如系统异常,系统重启),数据库引擎会怎么做?
由于未完成第一步,提交指令还未记录到磁盘的事务日志中,此时事务并未持久化,系统发生故障后,SQL Server
会检查每个数据库的事务日志,进行恢复处理(恢复处理一般分为重做阶段和撤销阶段),此时的恢复处理为重做阶段,即提交指令还未记录到磁盘的事务日志中,
数据库引擎会撤销这些事务所做的所有修改,这个过程也成为回滚。
问题2:完成如上第一步但还未完成第二步,系统发生故障(如系统异常,系统重启),数据库引擎会怎么做?
完成第一步后,提交指令已记录到磁盘的事务日志中,无论数据操作是否被写入到磁盘的数据分区,此时事务已持久化,系统发生故障后,SQL Server
会检查每个数据库的事务日志,进行恢复处理(恢复处理一般分为重做阶段和撤销阶段),此时的恢复处理为重做阶段,即由于数据修改还没有运用到数据分区的事务,
数据库引擎会重做这些事务所做的所有修改,这个过程也成为前滚。
三 事务的隔离级别和隔离级别产生的一致性问题
1 未提交读(READ UNCOMMITTED)
未提交读(READ UNCOMMITTED)指读取未提交的数据,此时产生的数据不一致性,我们称为数据脏读。
1.1 未提交读为什么会产生数据脏读
未提交读是最低级的隔离级别,在这个隔离级别运行的事务,读操作是不需要请求共享锁的,如果读操作不需要共享锁,就不会产生与持有排它锁的事务操作发生冲突,
那么也就是说,在这个事务隔离级别,读操作可以与写操作同时进行,互不排斥,读操作可以读取写操作未提交的修改,从而造成数据的不一致性,这种情况,我们称
数据脏读。
1.2 图解数据脏读

1.3 SQL演示数据脏读

2 已提交读(READ COMMITTED)
已提交读(READ COMMITTED)指只能读取已提交事务的数据,是防止数据脏读的最低隔离级别,也是SQL Server默认的隔离级别,它要求读操作必须获得共享锁后
才能进行操作,防止读取未提交的修改,虽然已提交读能防止产生数据脏读,但却不可避免不可重复读数据一致性问题。
2.1 为什么已提交读能够防止数据脏读
已提交读只允许读取事务已提交的数据,它要求读操作必须获得共享锁才能尽心操作,而读操作的共享锁与写操作的排他锁是互斥的,两者互斥会发生冲突,所以读操作
在读取数据时,必须等待写操作完成后,才能获取共享锁,然后才能读取数据,此时读取的数据是已经提交结束的数据,因此就防止了数据脏读的问题。
2.2 SQL演示已提交读

2.3 为什么已提交读会产生不可重复读问题
我们知道,虽然已提交读能获得共享锁,然而,读操作一完成,就会立即释放资源上的共享锁(该操作不会在事务持续期间一致保留共享锁),如此就会产生一个问题,
即在一个事务处理内部对相同数据资源读操作之间,没有共享锁会锁定该资源,导致其他事务可以在两个读操作之间更改数据资源,读操作因而可能每次得到不同的
取值,这种现象称为数据的不可重复读。
2.4 图解不可重复读

3 可重复读(REPEATABLE READ)
为了防止不可重复读现象,SQL Sever中采用隔离级别升级的方式,即将已提交读升级为可重复读。在可重复读隔离级别下,事务中的读操作不仅能获得共享锁,
而且获得的共享锁一直保持到事务完成为止, 在该事务完成之前,其他事务不可能获得排他锁来修改这一数据,如此,便实现了可重复读,防止了不可重复读造
成的数据不一致性。可重复读不仅能解决不可重复读数据不一致性问题,还能解决丢失更新问题。然而,可重复读也存在问题,那就是死锁和幻读等问题。
3.1 SQL演示可重复读

3.2 何为丢失更新?
在比可重复读低的隔离级别中,两个事务在读取数据之后就不再持有该资源的任何锁,此时,两个事务都能更新这个值,
从而发生最后事务更新的值覆盖前面事务更新的值,从而造成数据的丢失,这称为丢失更新。
3.3 图解丢失更新

4 可序列化(SERIALIZABLE)
4.1 何为幻读?
我们知道,在可重复读隔离级别下,读事务持有的共享锁一直保持到该事务完成为止,但是事务只锁定查询第一次运行时找到的那些数据资源(如,行),
而不会锁定查询结果范围以外的其他行(其实,控制事务时,有数据库架构级别,表,页和行等)。因此,在同一事务中进行第二次读取之前,若其他事
务插入新行,并且新行能满足读操作的查询过滤条件,那么这些新行也会出现在第二次读操作返回的结果中,这些新行称为幻影子,也叫做幻读。
4.2 图解幻读

4.3 如何解决幻读?
SQL SERVER中,更高级别的可序列化(SERIALIZABLE)能够解决该问题。
4.4 何为可序列化(SERIALIZABLE)?
大多数时候,可序列化(SERIALIZABLE)隔离级别的处理方式和可重复都得处理方式是类似的,只不过,可序列化(SERIALIZABLE)隔离级别
增加了一个新的内容——逻辑上,这个隔离级别会让读操作锁定满足查询搜索条件的键的整范围,这就意味着读操作不仅锁定了满足查询搜索
条件的现有的那些行,还锁定了未来可能满足查询搜索条件的行。
5 SNAPSHOT
略。
四 事务的隔离级别总结
下表总结了每种隔离级别与逻辑一致性问题,检测冲突和行版本控制之间关系

五 锁定
1 两种并发控制模型
关于并发控制模型,主要有两种,即悲观控制模型和乐观控制模型。

(1)悲观控制模型: 该模型假设总是存在多个事务对同一资源操作(读/写),即假定冲突总是会发生。在SQL Server中,采用事务
隔离级别来控制(也可叫做采用锁来控制)。一般在事务发生冲突前进行控制,也叫事前控制;
(2)乐观控制模型:该模型与悲观控制模型是对立的,即该模型总是假设系统中并不存在或较少存在多个事务对同一资源操作(读/写)
,即假定冲突是不会发生的或很少发生的。在SQL Server中,采用行版本控制来处理。一般在事务发生冲突后进行控制,也叫事后
控制;
2 何为锁定及锁定的种类
2.1 何为锁定
锁定,指在并发操作时,确保数据的一致性所采用的一种手段。在SQL Server中,采用锁机制与事务隔离级别来控制数据的一致性,
2.2 锁定的种类
常用的四大类锁包括:共享锁,意向锁,更新锁和排他锁。

(1)共享锁:在SQL SERVER中,当事务要读取数据时,需要获取共享锁。
(2)意向锁:在SQL SERVER中,准确来说,意向锁并不是一种独立的锁,其主要作用在于获取锁的控制粒度(如,页,表,行等)。
(3)更新锁:在SQL SERVER中,准确来说,更新锁并不是一种独立的锁,而是由共享锁和排它锁组成的混合锁,其隔离级别高于共享锁,
低于排他锁,更新锁能够预防锁升级而产生的死锁。
(4)排它锁:在SQL SERVER中,当事务要写数据、更细数据和删除数据时,需要获取排他锁。
3 锁的控制粒度
在SQL SERVER中,锁可以控制表,页和行等资源。

六 参考文献
【01】Microsoft SqlServer 2008技术内幕:T-SQL 语言基础
【02】Microsoft SqlServer 2008技术内幕:T-SQL 查询
七 服务区
有喜欢的朋友,可以看一下,不喜欢的的朋友,勿喷,谢谢!!

八 版权区
- 感谢您的阅读,若有不足之处,欢迎指教,共同学习、共同进步。
- 博主网址:http://www.cnblogs.com/wangjiming/。
- 极少部分文章利用读书、参考、引用、抄袭、复制和粘贴等多种方式整合而成的,大部分为原创。
- 如您喜欢,麻烦推荐一下;如您有新想法,欢迎提出,邮箱:2016177728@qq.com。
- 可以转载该博客,但必须著名博客来源。
【SqlServer系列】浅谈SQL Server事务与锁(上篇)的更多相关文章
- 浅谈SQL Server事务与锁(上篇)
一 概述 在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章试图采用图文的方式来与大家一起探讨. “浅谈SQL Server 事务与锁”这个专题共分两篇,上篇主讲事务及 ...
- 浅谈SQL Server内部运行机制
对于已经很熟悉T-SQL的读者,或者对于较专业的DBA来说,逻辑的增删改查,或者较复杂的SQL语句,都是非常简单的,不存在任何挑战,不值得一提,那么,SQL的哪些方面是他们的挑战 或者软肋呢? 那就是 ...
- SQL SERVER 事务和锁
内容皆整理自网络 一.事务 作者:郭无心链接:https://www.zhihu.com/question/31346392/answer/59815366来源:知乎著作权归作者所有.商业转载请联系作 ...
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
- 浅谈SQL Server数据内部表现形式
在上篇文章 浅谈SQL Server内部运行机制 中,与大家分享了SQL Server内部运行机制,通过上次的分享,相信大家已经能解决如下几个问题: 1.SQL Server 体系结构由哪几部分组成? ...
- 浅谈SQL Server中的事务日志(一)----事务日志的物理和逻辑构架
简介 SQL Server中的事务日志无疑是SQL Server中最重要的部分之一.因为SQL SERVER利用事务日志来确保持久性(Durability)和事务回滚(Rollback).从而还部分确 ...
- 浅谈SQL Server中的事务日志(三)----在简单恢复模式下日志的角色
简介 在简单恢复模式下,日志文件的作用仅仅是保证了SQL Server事务的ACID属性.并不承担具体的恢复数据的角色.正如”简单”这个词的字面意思一样,数据的备份和恢复仅仅是依赖于手动备份和恢复.在 ...
- 浅谈SQL Server中的事务日志(五)----日志在高可用和灾难恢复中的作用
简介 日志的作用是保证持久性和数据一致性,通过日志可以实现数据的Undo与Redo,因此通过日志,SQL Server不仅仅可以实现灾难恢复,还可以通过日志的Redo来实现高可用性.本篇文章主要讲述日 ...
- 浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色
简介 每一个SQL Server的数据库都会按照其修改数据(insert,update,delete)的顺序将对应的日志记录到日志文件.SQL Server使用了Write-Ahead logging ...
随机推荐
- JavaScript(一)js简单介绍
JavaScript JS历史简述: javascript 是 netscape 网景公司 的 布兰德·艾奇 研发的, 网景要求 布兰德·艾奇 10天开发出来一个与Java相似 但要比java简 ...
- 推荐一个比HtmlWebpackPlugin更灵活的插件
插件:html-res-webpack-plugin https://github.com/lcxfs1991/html-res-webpack-plugin/blob/v3/README_ZH.md ...
- 闲来无事,把node又拾起来看看
处在国企单位,整天闲的要死要死的,民族的花朵都快枯萎了 哎呀呀,打起精神.......早睡早起,多看书...开始进入苦读状态,苦练武功,争取有朝一日报效祖国...哈哈 开玩笑的 开始看书吧 记得N ...
- Android数据库之判断表是否存在
Android开发的时候我们可能会用到它的本地数据库,在使用的时候有可能我们已经储存了数据了,但是,我们的表已经创建了,里面有数据,我们要怎么判断表是否已经创建可能就需要琢磨一下. 以下便是利用了,查 ...
- typeof关键字的作用
http://blog.chinaunix.net/uid-28458801-id-4200573.html 一.typeof详解: 前言: typeof关键字是C语言中的一个新扩展,这个特性在 ...
- 学习 node.js 搭建web服务器
开始 学习使用 node.js 首先完成搭建一个 web服务器.myweb.js var http = require('http'); var url = require('url'); var h ...
- 记录因webpack版本问题导致vue-cli快速搭建的项目运行时报错!
今日突然在群里见到好几个小伙伴说在创建vue项目后不能跑,会报错. 刚开始还不信,花了几分钟时间自己试了下,还真报错了!如下图 小伙伴的报错,如下图! 百思不得其解,看了运行的日志也找不出原因.于 ...
- 进行app性能和安全性测试的重要性
如何让用户感觉App运行速度更快呢,这需要对App进行性能测试.限制App性能的因素按照App的系统结构分为App自身和App需要用到的后台服务. 测试App连接网络的速度 一般采用在模拟Mock环境 ...
- 【Java学习笔记之十四】Java中this用法小节
用类名定义一个变量的时候,定义的只是一个引用,外面可以通过这个引用来访问这个类里面的属性和方法. 那们类里面是够也应该有一个引用来访问自己的属性和方法纳? 呵呵,JAVA提供了一个很好的东西,就是 t ...
- “玲珑杯”ACM比赛 Round #19题解&源码【A,规律,B,二分,C,牛顿迭代法,D,平衡树,E,概率dp】
A -- simple math problem Time Limit:2s Memory Limit:128MByte Submissions:1599Solved:270 SAMPLE INPUT ...