SQL SERVER中事务和锁的简要理解
2013-11-24 01:11
288 查看
前言
阅读本文前建议先对事务有过基本的了解,有使用过事务,听过“锁”这个概念,希望快速了解这些概念并应用到实际开发中去。
对于事务和锁的详细解说可以参考http://blog.csdn.net/happyflystone/article/list/1中的事务和锁系列,本文只是试图用最简单的语言(甚至不太精准)来帮助初学者理解锁和事务的概念。若要更加精准、全面和深入的概念请自行阅读相关资料。
什么?你说你没用过事务?没用过锁?
其实你一直在用,数据库已经默认在使用了,只是你没感觉到而已。
其实默认情况下,你的每一个增删改查,修改数据库对象,数据库都会自动使用使用事务,同时就用到了锁,数据库会根据你的操作自动使用不同的锁。数据库默认使用“提交读”级别的隔离级别。
下面先讲锁。
锁
操作资源时先锁住资源。锁的作用是隔离数据库的操作,防止并发访问下的数据错乱(具体有哪些错乱请参见/article/2559969.html)。
也就是说,在操作资源时,不准其他人来捣乱,要把其他人隔离到一边等着。
上面讲的“操作"包括增,删,改,查,修改对象等操作。
我们在做不同的操作时,数据库会自动使用锁,先锁住资源。针对不同的访问可以有不同的锁。
以下是几项最基本的锁(详情请参见MSDN:锁定 [SQL Server], 模式)。
1、 读取数据时的“共享锁”。
在读数据时,若还没读完,其他人不要来修改数据,但其他人可以一起读数据。
2、 更新数据时用“更新锁”。
其实更新数据分为两个过程,第一个过程是读取待修改的行,第二个过程是正式修改数据。
在更新数据时,可以想象有很多行数据要一行一行修改,若还全部没修改完,其他人就不要来读数据,因为读到的数据也是不完整的,除非明确指示愿意读这些脏数据(使用with(nolock)提示);同时其他人绝对不允许中途改数据,至少等我改完了再来改。另外,在更新数据时,表结构也不能改,要是把我要更改的字段都删掉了那我还改什么!要么在我操作前就删除,要么等我操作以后再删。
3、 删除与插入数据时会有“排它锁”.
类似于更新数据,在删除和插入期间,不允许别人来读数据,,除非你明确指示愿意读这些脏数据(使用with(nolock)提示。同时,不管你愿不愿意,都绝对不允许来中途改我的数据。要等我全部改完了其他才能操作。
4、 修改视图,函数等数据对象时会有“架构锁”
修改数据库架构时也不允许其他人来操作。比如我正在删除一个表,你还想来读这个表的数据?明显不可能。
5、 上述锁在真正生效前还会有“意向锁”,就是锁资源前先发布声明:“我要锁资源了,其他人在外边等着,不要强行进来和我抢资源!”,意向锁可以和前面的基本锁进行组合。意向锁的好处当然就是事先通知其他人,免得其他人强行闯进来抢资源,再被暴力赶出去,因为这种“强行抢”和“暴力赶”的成本不低。
锁针对的是数据库资源,哪些资源会被数据库“锁”呢?最基本的有数据行,数据页,数据表,数据文件,甚至整个数据库(详情请参见MSDN:锁定 [SQL Server], 可锁定资源)。
上面讲完了各种基本锁的基础概念,大概对锁有了一个了解,那在我们实际的开发过程中如何使用呢?光看猪跑不吃猪肉没意思吧?
前面已经说到数据库会自动使用锁,而实际上我们可以用一些提示信息(参见MSDN:表提示)指示在一条SQL语句中,数据库使用哪种锁,但是需要事先声明的是,提示终归只是提示,你无法强制数据库做不符合数据规则的事。
接下来讲事务。
事务
简单来说,在使用过程中,事务就是把许多SQL语句打包成一个整体执行,这些语句要么全部成功,要么全部失败。
当然,上面这句只描述了事务的“原子性”(为什么叫“原子”?原子在化学反应中被认为是不可再分割的最小单位),事实上事务还有其他特性(一致性,隔离性,持久性),这里重点讲隔离性。
前面讲锁的时候就提到了“隔离”,那事务的隔离与锁的隔离有什么区别呢?(专家们不要笑,这问题曾经困扰了我许久,概念太多,很绕的)
事实上事务的隔离就是锁的隔离,事务的隔离是通过锁来实现的,事务只是可以设置隔离的级别,而不同的隔离级别只是控制了锁的粒度(可以暂时粗暴地把“粒度”一词理解为“力度”或“级别”),或者说,发生事务时使用什么锁,锁什么资源,锁多久(这个说法不是完全地精准,但可先粗略地这样理解)。
事务有以下几种基本的隔离级别(详情请参见MSDN:锁定 [SQL Server], 隔离级别)
在上面表中你或许已经发现了一些问题。
1、 每一个隔离级别都是解决上一个隔离级别中未能解决的问题。
2、 不同的隔离级别都只是“共享锁”,也就是说只影响读数据?
答:是的,如你所见。隔离级别控制的就是读数据。
3、 那更新数据呢?为什么没有脏写?难道事务的锁不管吗?
答:不管你用什么隔离级别,同一个事务中,只要有更新或删除数据,这个排它锁就会持续到最后才释放。也就是说,不管如何隔离,哪怕是使用“未提交读”,事务都会保证不脏写。
4、 不可重复读和幻想读到底有什么区别?看上去貌似是一样的。
答:如表格中所述,不可重复读,只是指,在同一个事务内,已经读取到的数据行在第二次读取时行内的数据发生了变化。而幻像读是指,已经读取到了数据,第二次读时,就多出新行了。这两种级别是不一样的,一种是修改行,一种是新增行,尽管差别小,但仍是两个级别。
接下来讲讲如何在开发中使用事务及隔离级别。
其实从上面的示例语句差异来看,都只是Read后的关键字不一样,也就表示事务隔离级别就是针对读数据的。
那用事务就是为了锁住读数据,即隔离数据吗?
当然不是,隔离只是事务的一个特性。我们平时用事务多用的是事务的“原子性”,也就是一个事务可以有多批语句,可以把这些语句当作一个整体来执行,并利用事务的”持久性",一次性提交或回滚所有的操作。
阅读本文前建议先对事务有过基本的了解,有使用过事务,听过“锁”这个概念,希望快速了解这些概念并应用到实际开发中去。
对于事务和锁的详细解说可以参考http://blog.csdn.net/happyflystone/article/list/1中的事务和锁系列,本文只是试图用最简单的语言(甚至不太精准)来帮助初学者理解锁和事务的概念。若要更加精准、全面和深入的概念请自行阅读相关资料。
什么?你说你没用过事务?没用过锁?
其实你一直在用,数据库已经默认在使用了,只是你没感觉到而已。
其实默认情况下,你的每一个增删改查,修改数据库对象,数据库都会自动使用使用事务,同时就用到了锁,数据库会根据你的操作自动使用不同的锁。数据库默认使用“提交读”级别的隔离级别。
下面先讲锁。
锁
操作资源时先锁住资源。锁的作用是隔离数据库的操作,防止并发访问下的数据错乱(具体有哪些错乱请参见/article/2559969.html)。
也就是说,在操作资源时,不准其他人来捣乱,要把其他人隔离到一边等着。
上面讲的“操作"包括增,删,改,查,修改对象等操作。
我们在做不同的操作时,数据库会自动使用锁,先锁住资源。针对不同的访问可以有不同的锁。
以下是几项最基本的锁(详情请参见MSDN:锁定 [SQL Server], 模式)。
1、 读取数据时的“共享锁”。
在读数据时,若还没读完,其他人不要来修改数据,但其他人可以一起读数据。
2、 更新数据时用“更新锁”。
其实更新数据分为两个过程,第一个过程是读取待修改的行,第二个过程是正式修改数据。
在更新数据时,可以想象有很多行数据要一行一行修改,若还全部没修改完,其他人就不要来读数据,因为读到的数据也是不完整的,除非明确指示愿意读这些脏数据(使用with(nolock)提示);同时其他人绝对不允许中途改数据,至少等我改完了再来改。另外,在更新数据时,表结构也不能改,要是把我要更改的字段都删掉了那我还改什么!要么在我操作前就删除,要么等我操作以后再删。
3、 删除与插入数据时会有“排它锁”.
类似于更新数据,在删除和插入期间,不允许别人来读数据,,除非你明确指示愿意读这些脏数据(使用with(nolock)提示。同时,不管你愿不愿意,都绝对不允许来中途改我的数据。要等我全部改完了其他才能操作。
4、 修改视图,函数等数据对象时会有“架构锁”
修改数据库架构时也不允许其他人来操作。比如我正在删除一个表,你还想来读这个表的数据?明显不可能。
5、 上述锁在真正生效前还会有“意向锁”,就是锁资源前先发布声明:“我要锁资源了,其他人在外边等着,不要强行进来和我抢资源!”,意向锁可以和前面的基本锁进行组合。意向锁的好处当然就是事先通知其他人,免得其他人强行闯进来抢资源,再被暴力赶出去,因为这种“强行抢”和“暴力赶”的成本不低。
锁针对的是数据库资源,哪些资源会被数据库“锁”呢?最基本的有数据行,数据页,数据表,数据文件,甚至整个数据库(详情请参见MSDN:锁定 [SQL Server], 可锁定资源)。
上面讲完了各种基本锁的基础概念,大概对锁有了一个了解,那在我们实际的开发过程中如何使用呢?光看猪跑不吃猪肉没意思吧?
前面已经说到数据库会自动使用锁,而实际上我们可以用一些提示信息(参见MSDN:表提示)指示在一条SQL语句中,数据库使用哪种锁,但是需要事先声明的是,提示终归只是提示,你无法强制数据库做不符合数据规则的事。
锁类型 | 关键字 | 示例 | 说明 |
不加锁 | Nolock | Select * from table with(nolock) | 不管别人怎么锁住了数据,我都要读出来。但写数据的锁定规则不变。 |
共享锁 | HoldLock | Select * from table with(HoldLock) | |
更新锁 | UpdLock | Select * from table with(UpdLock) | |
跳过锁 | ReadPast | Select * from table with(ReadPast) | |
排它锁 | XLock | Select * from table with(XLock) |
事务
简单来说,在使用过程中,事务就是把许多SQL语句打包成一个整体执行,这些语句要么全部成功,要么全部失败。
当然,上面这句只描述了事务的“原子性”(为什么叫“原子”?原子在化学反应中被认为是不可再分割的最小单位),事实上事务还有其他特性(一致性,隔离性,持久性),这里重点讲隔离性。
前面讲锁的时候就提到了“隔离”,那事务的隔离与锁的隔离有什么区别呢?(专家们不要笑,这问题曾经困扰了我许久,概念太多,很绕的)
事实上事务的隔离就是锁的隔离,事务的隔离是通过锁来实现的,事务只是可以设置隔离的级别,而不同的隔离级别只是控制了锁的粒度(可以暂时粗暴地把“粒度”一词理解为“力度”或“级别”),或者说,发生事务时使用什么锁,锁什么资源,锁多久(这个说法不是完全地精准,但可先粗略地这样理解)。
事务有以下几种基本的隔离级别(详情请参见MSDN:锁定 [SQL Server], 隔离级别)
隔离级别 | 使用的锁 | 锁住的资源 | 锁的时间 | 不能解决的问题 |
未提交读 | 无锁 | 不锁资源 | 无 | 别的事务还未更新完数据你就能直接读出来,脏读 |
已提交读 | 共享锁 | 仅读取的行 | 访问完就释放 | 你刚读取完数据行,再读时,原来行中的数据就不一样了,这叫不可重复读 |
可重复读 | 共享锁 | 仅读取的行 | 到事务结束 | 你刚读取完数据行,尽管原来读到的数据不会改,但再读时就可能多了新行了(不会少行哦!),这叫幻像读。 |
可串行化 | 共享锁 | 整个SQL语句可能涉及的范围,包括后面插入的行。 | 到事务结束 | 所有问题都解决了,不会有脏读,不可重复读和幻像读 |
1、 每一个隔离级别都是解决上一个隔离级别中未能解决的问题。
2、 不同的隔离级别都只是“共享锁”,也就是说只影响读数据?
答:是的,如你所见。隔离级别控制的就是读数据。
3、 那更新数据呢?为什么没有脏写?难道事务的锁不管吗?
答:不管你用什么隔离级别,同一个事务中,只要有更新或删除数据,这个排它锁就会持续到最后才释放。也就是说,不管如何隔离,哪怕是使用“未提交读”,事务都会保证不脏写。
4、 不可重复读和幻想读到底有什么区别?看上去貌似是一样的。
答:如表格中所述,不可重复读,只是指,在同一个事务内,已经读取到的数据行在第二次读取时行内的数据发生了变化。而幻像读是指,已经读取到了数据,第二次读时,就多出新行了。这两种级别是不一样的,一种是修改行,一种是新增行,尽管差别小,但仍是两个级别。
接下来讲讲如何在开发中使用事务及隔离级别。
隔离级别 | 关键字 | 示例 | 说明 |
未提交读 | READ UNCOMMITTED | SET TRANSACTIONISOLATIONLEVELREADUNCOMMITTED Begin tran Select *fromsysobject scommit | |
已提交读 | READ COMMITTED | SET TRANSACTIONISOLATIONLEVELREADCOMMITTED Begin tran Select *fromsysobjects commit | |
可重复读 | REPEATABLE READ | SET TRANSACTIONISOLATIONLEVELREPEATABLEREAD Begin tran Select *fromsysobject scommit | |
可串行化 | SERIALIZABLE | SET TRANSACTIONISOLATIONlevelSERIALIZABLE Begin tran Select *fromsysobjects commit |
那用事务就是为了锁住读数据,即隔离数据吗?
当然不是,隔离只是事务的一个特性。我们平时用事务多用的是事务的“原子性”,也就是一个事务可以有多批语句,可以把这些语句当作一个整体来执行,并利用事务的”持久性",一次性提交或回滚所有的操作。
相关文章推荐
- 关于SQL Server中事务的理解
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
- 对SQL Server事务的4个隔离级别的理解
- 对于事务和同步(并发)的简要理解
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
- 转载--关于SQL Server中事务的理解
- 理解Sql Server 事务隔离层级(Transaction Isolation Level)
- SQL Server:无法启动 MS DTC 事务管理器--解决方案
- spring事务概念理解
- 从源码理解spring事务(1)
- SQL SERVER事务复制--工作原理测试
- 理解事务——原子性、一致性、隔离性和持久性
- 设计----【分布式事务】深入理解分布式事务,高并发下分布式事务的解决方案
- 事务是什么?有哪些属性,并简要说明这些属性的含义。
- SQL SERVER存储过程中如何使用事务与try catch
- [Mysql]——通过例子理解事务的4种隔离级别(转)
- SQL Server 事务、异常和游标