了解事务和锁

事务:保持逻辑数据一致性与可恢复性,必不可少的利器。

锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不能保证数据的安全正确读写。

死锁:是数据库性能的重量级杀手之一,而死锁却是不同事务之间抢占数据资源造成的。

不懂的听上去,挺神奇的,懂的感觉我在扯淡,下面带你好好领略下他们的风采,嗅査下他们的狂骚。。

先说事务--概念,分类

用华仔无间道中的一句来给你诠释下:去不了终点,回到原点。

举例说明:

在一个事务中,你写啦2条sql语句,一条是修改订单表状态,一条是修改库存表库存-1 。 如果在修改订单表状态的时候出错,事务能够回滚,数据将恢复到没修改之前的数据状态,下面的修改库存也就不执行,这样确保你关系逻辑的一致,安全。。

事务就是这个样子,倔脾气,要么全部执行,要么全部不执行,回到原数据状态。

书面解释:事务具有原子性,一致性,隔离性,持久性。

  • 原子性:事务必须是一个自动工作的单元,要么全部执行,要么全部不执行。
  • 一致性:事务结束的时候,所有的内部数据都是正确的。
  • 隔离性:并发多个事务时,各个事务不干涉内部数据,处理的都是另外一个事务处理之前或之后的数据。
  • 持久性:事务提交之后,数据是永久性的,不可再回滚。

然而在SQL Server中事务被分为3类常见的事务:

  • 自动提交事务:是SQL Server默认的一种事务模式,每条Sql语句都被看成一个事务进行处理,你应该没有见过,一条Update 修改2个字段的语句,只修该了1个字段而另外一个字段没有修改。。
  • 显式事务:T-sql标明,由Begin Transaction开启事务开始,由Commit Transaction 提交事务、Rollback Transaction 回滚事务结束。
  • 隐式事务:使用Set IMPLICIT_TRANSACTIONS ON 将将隐式事务模式打开,不用Begin Transaction开启事务,当一个事务结束,这个模式会自动启用下一个事务,只用Commit Transaction 提交事务、Rollback Transaction 回滚事务即可。

显式事务的应用

常用语句就四个。

  • Begin Transaction:标记事务开始。
  • Commit Transaction:事务已经成功执行,数据已经处理妥当。
  • Rollback Transaction:数据处理过程中出错,回滚到没有处理之前的数据状态,或回滚到事务内部的保存点。
  • Save Transaction:事务内部设置的保存点,就是事务可以不全部回滚,只回滚到这里,保证事务内部不出错的前提下。

建表t_top_ten 插入数据如下

 USE T4st
GO
BEGIN
INSERT INTO [dbo].[t_top_ten]
(Id,
Name)
VALUES(1,'第一名'),(2,'第二名'),(3,'第三名'),(4,'第四名'),(5,'第五名')
END
GO

建立事务--当条件语句成立--回滚事务

 USE T4st
GO BEGIN TRANSACTION
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(6,'第六名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(7,'第七名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(8,'第八名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(9,'第九名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(10,'第十名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(11,'第十一名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(12,'第十二名') DECLARE @rank INT
SELECT @rank = (SELECT COUNT(1) FROM [dbo].[t_top_ten])
IF(@rank > 8)
BEGIN
ROLLBACK TRANSACTION
PRINT '超过范围'
END
ELSE
BEGIN
COMMIT TRANSACTION
PRINT '成功'
END
GO

或可设置保存点

USE T4st
GO --SET XACT_ABORT OFF BEGIN TRAN
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(6,'第六名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(7,'第七名')
SAVE TRAN pigOneIn
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(8,'第八名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(9,'第九名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(10,'第十名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(11,'第十一名')
INSERT INTO [dbo].[t_top_ten] (Id,Name) VALUES(12,'第十二名') DECLARE @rank INT
SELECT @rank = (SELECT COUNT(1) FROM [dbo].[t_top_ten])
IF(@rank > 8)
BEGIN
--ROLLBACK TRANSACTION
--PRINT '超过范围'
ROLLBACK TRAN pigOneIn
SELECT * FROM [dbo].[t_top_ten]
END
ELSE
BEGIN
COMMIT TRANSACTION
PRINT '成功'
END
GO

使用set xact_abort

设置 xact_abort on/off , 指定是否回滚当前事务,为on时如果当前sql出错,回滚整个事务,为off时如果sql出错回滚当前sql语句,其它语句照常运行读写数据库。

需要注意的时:xact_abort只对运行时出现的错误有用,如果sql语句存在编译时错误,那么他就失灵啦。

事务把死锁给整出来啦

跟着做:打开两个查询窗口,把下面的语句,分别放入2个查询窗口,在5秒内运行2个事务模块。

begin tran
update lives set play='羽毛球'
waitfor delay '0:0:5'
update dbo.Earth set Animal='老虎'
commit tran
begin tran
update Earth set Animal='老虎'
waitfor delay '0:0:5' --等待5秒执行下面的语句
update lives set play='羽毛球'
commit tran
select * from lives
select * from Earth

为什么呢,下面我们看看锁,什么是锁。

并发事务成败皆归于锁——锁定

在多用户都用事务同时访问同一个数据资源的情况下,就会造成以下几种数据错误。

  • 更新丢失:多个用户同时对一个数据资源进行更新,必定会产生被覆盖的数据,造成数据读写异常。
  • 不可重复读:如果一个用户在一个事务中多次读取一条数据,而另外一个用户则同时更新啦这条数据,造成第一个用户多次读取数据不一致。
  • 脏读:第一个事务读取第二个事务正在更新的数据表,如果第二个事务还没有更新完成,那么第一个事务读取的数据将是一半为更新过的,一半还没更新过的数据,这样的数据毫无意义。
  • 幻读:第一个事务读取一个结果集后,第二个事务,对这个结果集经行增删操作,然而第一个事务中再次对这个结果集进行查询时,数据发现丢失或新增。

然而锁定,就是为解决这些问题所生的,他的存在使得一个事务对他自己的数据块进行操作的时候,而另外一个事务则不能插足这些数据块。这就是所谓的锁定。

死锁

什么是死锁,为什么会产生死锁。我用 “事务把死锁给整出来啦” 标题下的两个事务产生的死锁来解释应该会更加生动形象点。

例子是这样的:

第一个事务(称为A):先更新lives表 --->>停顿5秒---->>更新earth表

第二个事务(称为B):先更新earth表--->>停顿5秒---->>更新lives表

先执行事务A----5秒之内---执行事务B,出现死锁现象。

过程是这样子的:

  1. A更新lives表,请求lives的排他锁,成功。
  2. B更新earth表,请求earth的排他锁,成功。
  3. 5秒过后
  4. A更新earth,请求earth的排它锁,由于B占用着earth的排它锁,等待。
  5. B更新lives,请求lives的排它锁,由于A占用着lives的排它锁,等待。

这样相互等待对方释放资源,造成资源读写拥挤堵塞的情况,就被称为死锁现象,也叫做阻塞。而为什么会产生,上例就列举出来啦。

然而数据库并没有出现无限等待的情况,是因为数据库搜索引擎会定期检测这种状况,一旦发现有情况,立马选择一个事务作为牺牲品。牺牲的事务,将会回滚数据。有点像两个人在过独木桥,两个无脑的人都走在啦独木桥中间,如果不落水,必定要有一个人给退回来。这种相互等待的过程,是一种耗时耗资源的现象,所以能避则避。

哪个人会被退回来,作为牺牲品,这个我们是可以控制的。控制语法:

set deadlock_priority  <级别>

死锁处理的优先级别为 low<normal<high,不指定的情况下默认为normal,牺牲品为随机。如果指定,牺牲品为级别低的。

还可以使用数字来处理标识级别:-10到-5为low,-5为normal,-5到10为high。

 USE T4st

 set DEADLOCK_PRIORITY 0

 begin tran
update Earth set Animal='老虎'
waitfor delay '0:0:5' --等待5秒执行下面的语句
update lives set play='羽毛球'
commit tran
select * from lives
select * from Earth
 USE T4st

 set DEADLOCK_PRIORITY 6

 begin tran
update lives set play='羽毛球'
waitfor delay '0:0:5'
update dbo.Earth set Animal='老虎'
commit tran

减少死锁的发生,提高数据库性能

死锁耗时耗资源,然而在大型数据库中,高并发带来的死锁是不可避免的,所以我们只能让其变的更少。

  1. 按照同一顺序访问数据库资源,上述例子就不会发生死锁啦
  2. 保持是事务的简短,尽量不要让一个事务处理过于复杂的读写操作。事务过于复杂,占用资源会增多,处理时间增长,容易与其它事务冲突,提升死锁概率。
  3. 尽量不要在事务中要求用户响应,比如修改新增数据之后在完成整个事务的提交,这样延长事务占用资源的时间,也会提升死锁概率。
  4. 尽量减少数据库的并发量。
  5. 尽可能使用分区表,分区视图,把数据放置在不同的磁盘和文件组中,分散访问保存在不同分区的数据,减少因为表中放置锁而造成的其它事务长时间等待。
  6. 避免占用时间很长并且关系表复杂的数据操作。
  7. 使用较低的隔离级别,使用较低的隔离级别比使用较高的隔离级别持有共享锁的时间更短。这样就减少了锁争用。

可参考:http://msdn.microsoft.com/zh-cn/library/ms191242(v=sql.105).aspx

查看锁活动情况:

--查看锁活动情况
select * from sys.dm_tran_locks
--查看事务活动情况
dbcc opentran

可参考:http://msdn.microsoft.com/zh-cn/library/ms190345.aspx

为事务设置隔离级别

所谓事物隔离级别,就是并发事务对同一资源的读取深度层次。分为5种。

  • read uncommitted:这个隔离级别最低啦,可以读取到一个事务正在处理的数据,但事务还未提交,这种级别的读取叫做脏读。
  • read committed:这个级别是默认选项,不能脏读,不能读取事务正在处理没有提交的数据,但能修改。
  • repeatable read:不能读取事务正在处理的数据,也不能修改事务处理数据前的数据。
  • snapshot:指定事务在开始的时候,就获得了已经提交数据的快照,因此当前事务只能看到事务开始之前对数据所做的修改。
  • serializable:最高事务隔离级别,只能看到事务处理之前的数据。
--语法
set tran isolation level <级别>

read uncommitted隔离级别的例子:

begin tran
set deadlock_priority low
update Earth set Animal='老虎'
waitfor delay '0:0:5' --等待5秒执行下面的语句
rollback tran

开另外一个查询窗口执行下面语句

set tran isolation level read uncommitted
select * from Earth --读取的数据为正在修改的数据 ,脏读
waitfor delay '0:0:5' --5秒之后数据已经回滚
select * from Earth --回滚之后的数据

read committed隔离级别的例子:

begin tran
update Earth set Animal='老虎'
waitfor delay '0:0:10' --等待5秒执行下面的语句
rollback tran
set tran isolation level read committed
select * from Earth ---获取不到老虎,不能脏读
update Earth set Animal='猴子1' --可以修改
waitfor delay '0:0:10' --10秒之后上一个事务已经回滚
select * from Earth --修改之后的数据,而不是猴子

剩下的几个级别,不一一列举啦,自己理解吧。

设置锁超时时间

发生死锁的时候,数据库引擎会自动检测死锁,解决问题,然而这样子是很被动,只能在发生死锁后,等待处理。

然而我们也可以主动出击,设置锁超时时间,一旦资源被锁定阻塞,超过设置的锁定时间,阻塞语句自动取消,释放资源,报1222错误。

好东西一般都具有两面性,调优的同时,也有他的不足之处,那就是一旦超过时间,语句取消,释放资源,但是当前报错事务,不会回滚,会造成数据错误,你需要在程序中捕获1222错误,用程序处理当前事务的逻辑,使数据正确。

--查看超时时间,默认为-1
select @@lock_timeout
--设置超时时间
set lock_timeout 0 --为0时,即为一旦发现资源锁定,立即报错,不在等待,当前事务不回滚,设置时间需谨慎处理后事啊,你hold不住的。

仔细阅读,希望能分享给你一点点东西,谢谢,over。

sql service 事务与锁的更多相关文章

  1. 【SqlServer系列】浅谈SQL Server事务与锁(上篇)

    一  概述 在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章视图采用图文的方式来与大家一起探讨. “浅谈SQL Server 事务与锁”这个专题共分两篇,上篇主讲事务及 ...

  2. SQL SERVER 事务和锁

    内容皆整理自网络 一.事务 作者:郭无心链接:https://www.zhihu.com/question/31346392/answer/59815366来源:知乎著作权归作者所有.商业转载请联系作 ...

  3. 13Microsoft SQL Server SQL 高级事务,锁,游标,分区

    Microsoft SQL Server SQL高级事务,锁,游标,分区 通过采用事务和锁机制,解决了数据库系统的并发性问题. 9.1数据库事务 (1)BEGIN TRANSACTION语句定义事务的 ...

  4. 浅谈SQL Server事务与锁(上篇)

    一  概述 在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章试图采用图文的方式来与大家一起探讨. “浅谈SQL Server 事务与锁”这个专题共分两篇,上篇主讲事务及 ...

  5. SQL SERVICE中的锁

    SQL SERVICE中的几个锁 SELECT * FROM dbo.TableName WITH (NOLOCK) --不加任何锁的读,脏读SELECT * FROM dbo.TableName W ...

  6. SQL Server 事务与锁

    了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不能保证数据的安全正确读写. 死锁: ...

  7. sql server 事务和锁的作用

    事务 事务就是作为一个逻辑工作单元的SQL语句,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上个节点.为了确保要么执行,要么不执行,就可以使用事务.而锁是实现事务 ...

  8. SQL Server中的事务与锁

    了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不能保证数据的安全正确读写. 死锁: ...

  9. 【转】SQL Server中的事务与锁

    SQL Server中的事务与锁   了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂 ...

随机推荐

  1. 官方文档 恢复备份指南一 Introduction to Backup and Recovery

    1.备份分为:物理备份和逻辑备份    物理备份:备份数据文件  控制文件  归档日志文件     逻辑备份:EXP EXPDP备份等 物理备份为主,逻辑做补充     2.错误的类型         ...

  2. centos配置iptables

    第一次配置前消除默认的规则 #这个一定要先做,不然清空后可能会悲剧 iptables -P INPUT ACCEPT #清空默认所有规则 iptables -F #清空自定义的所有规则 iptable ...

  3. 王者荣耀交流协会beta冲刺贡献分分配结果

    根据原来约定的(贡献分分配规则){http://www.cnblogs.com/gaoyb348/p/7828523.html} 总共20个任务,一共35分,那么一个任务1.75分. 冉华完成了9个任 ...

  4. 创建、编译、执行 java程序

    java源文件(.java)——Java字节码文件(.class)——在java虚拟机上执行 其他语言很多是编译后执行,所以无法跨平台

  5. lintcode-171-乱序字符串

    171-乱序字符串 给出一个字符串数组S,找到其中所有的乱序字符串(Anagram).如果一个字符串是乱序字符串,那么他存在一个字母集合相同,但顺序不同的字符串也在S中. 注意事项 所有的字符串都只包 ...

  6. iOS- 显示数据列表最常用的一个控件UITableView

    相信做过iOS的程序员,最熟悉的控件一定少不了UITableView,最常用的控件也一定少不了UITableView! 今天分享一下自己对UITableView的实现大体思路,和整理出来的学习笔记! ...

  7. OSPF学习中的问题

    OSPF对接两方,对设置的要求,哪些参数必须相同 (HELLO &dead interval, area ID, authentation, 末节区域(option中的E位), network ...

  8. 3ds Max学习日记(八)

      再来更新一波学习进度.   之前玩了一下3dsmax里的灯光,不过由于和教程里的版本不同,教程里的我的没有,我有的教程又没有,所以只能瞎jb玩一玩.   最近又想建个人物模型玩玩,于是上网搜一下有 ...

  9. 【Redis】- 安装为windows服务

    1.安装redis服务 echo install redis-server redis-server.exe --service-install redis.windows.conf --loglev ...

  10. phpcms黄页,不能选择行业。解决办法

    用phpcms黄页模块,发布产品的时候.不能选择 产品分类,点开之后,啥都没有,是空的. 这个是因为:js的问题. 解决办法:将 网站根目录的 js 文件中的两个文件,更换为 官方的两个js文件.即可 ...