【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 ...
随机推荐
- [转]python变量作用域的有趣差别
func()里 可以访问全局变量i,但不能给i重新赋值. i = 1 def func(): print( i + 1) func() # 2 用global声明后,可以给i重新赋值. i = 1 d ...
- C# 实现邮件发送
要实现邮件发送功能首先需要准备两三个邮箱测试,在这里呢准备了2个QQ邮箱和一个微软邮箱,详细请看代码. 我这里是使用QQ邮箱向另外两个邮箱发送邮件的,在开始写代码之前你需要登录你QQ邮箱进行以下几个操 ...
- 【Java】CAS的乐观锁实现之AtomicInteger源码分析
1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及 ...
- 原生ajax jq跨域
原生js封装ajax //创建XmlhttpRequest对象 function createXHR(){ var xhr=null; if(XMLHttpRequest){ ...
- Java与算法之(12) - 老鼠再闯迷宫(广度优先算法)
贪吃的小老鼠又回来了,这次有什么新的办法吃到奶酪呢? 规则不变,只能上下左右在格子内移动. 因为上次的深度优先算法让老鼠走了不少冤枉路,这次老鼠带来了帮手探路鼠.探路鼠的使用规则如下: 小老鼠按右.下 ...
- Oracle实战笔记(第二天)
导读 今日主要内容:表管理.表操作(增删改查).表查询(简单查询&复杂查询).创建数据库. 一.表管理 1.表命名规范 必须以字母开头: 长度不能超过30个字符: 不能使用Oracle保留字: ...
- 1492: [NOI2007]货币兑换Cash
Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个 ...
- Java 大数类BigInteger和BigDecimal的基本函数
在Java中有两个类BigInteger和BigDecimal分别表示不可变的任意精度的整数和不可变的有符号的任意精度的十进制数(浮点数).主要用于高精度计算中.这两个类使得java中的大数,高精度运 ...
- 2017ecjtu-summer training #1 UVA 12050
A palindrome is a word, number, or phrase that reads the same forwards as backwards. For example, th ...
- HDU--2015
偶数求和 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...