SQL2005中的事务与锁定(三)- 转载
------------------------------------------------------------------------
-- Author : HappyFlyStone
-- Date : 2009-10-03 15:30:00
-- Version: Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86)
-- Apr 14 2006 01:12:25
-- Copyright (c) 1988-2005 Microsoft Corporation
-- Enterprise Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
-- 转载请注明出处,更多请关注:http://blog.csdn.net/happyflystone
-- 关键字:隔离等级 锁定 意外数据行为 Lock Hint
------------------------------------------------------------------------
在前面的两篇里我从纯理论上把事务相关的知识作了一个梳理,有人看了一定觉得无味了吧,好这一篇我们加入一点T-SQL语句把前面所说有东东关联起来,我们人为产生锁定来理解不同的意外数据行为在不同隔离等级下的表现,顺便再重温一下意外数据行及隔离等级,让大家对交易事务有一个直观的认识。
在进行实例前不得不先介绍一点锁的知识,注意这儿只是简单的说一下,不作深入讨论。我们根据用户访问资源的行为先归纳出几种锁,这几种锁在下面的实例里会出现,它们为:共享锁定、排它锁定、更新锁定及用意向这个限定词限定的三种锁(意向共享、意向排它、意向更新),当当然还有其它的模式,我们在下一篇再说。意向锁的存在是解决死锁的发生,保证进程在申请锁定前确定当前数据是否存在不兼容性的锁定。
先对上面提到的锁作一个简单的描述,更详细的下面再说。
共享锁定发生在查询记录时,直观就是我们select啦,但是并不是只有select才有共享锁定。一个查询记录的语句必须在没有与共享锁定互斥锁定存在或等待互斥锁定结束后,才能设置共享锁定并提取数据(互斥不互斥就是锁的兼容性,这在以后再说明)。
排它锁定发生在对数据增加、删除、修改时,事务开始以后语句申请并设置排它锁定(前提是没有其它互斥锁定存在),以明确告知其它进程对当前数据不可以查询或修改,等待事务结束后其它进程才可以查询或修改。
更新锁定是一个介于共享与排它之间的中继锁定,比如我们带where条件的update语句,在查询要更新的记录时是设置共享锁定,当要更新数据时这时锁定必须由共享锁定升级成更新锁定继而升级为排它锁定,当排它锁定设置成功才可以进行数据修改操作。显然也是要要求在锁升级的过程中没有互斥锁定的存在。简单的理解更新锁定是一个中继闸一样,把升级成排它锁定进程“序列化”,以解决死锁。最后重点说明一下,数据更新阶段是要对数据排它锁定不是更新锁定,不要被字面意思训导哦。
最后说一下在上述锁定模式下的互斥,共享锁定只与排它锁定互斥,更新锁定只与共享锁定不互斥。
在进行具体实例前我们一定要有一个工具来对我们实例过程进行监控,好,下面我写了一个过程,在需要时直接调用就行,过程如下:
Create Proc sp_us_lockinfo
---------------------------------------------------------------------
-- Author : HappyFlyStone
-- Date : 2009-10-03 15:30:00
-- BLOG : http://blog.csdn.net/happyflystone
-- 申明 :请保留作者信息,转载注明出处
--------------------------------------------------------------------
AS
BEGIN
SELECT
DB_NAME(t1.resource_database_id) AS [数据库名],
t1.resource_type AS [资源类型],
-- t1.request_type AS [请求类型],
t1.request_status AS [请求状态],
-- t1.resource_description AS [资源说明],
CASE t1.request_owner_type WHEN 'TRANSACTION' THEN '事务所有'
WHEN 'CURSOR' THEN '游标所有'
WHEN 'SESSION' THEN '用户会话所有'
WHEN 'SHARED_TRANSACTION_WORKSPACE' THEN '事务工作区的共享所有'
WHEN 'EXCLUSIVE_TRANSACTION_WORKSPACE' THEN '事务工作区的独占所有'
ELSE ''
END AS [拥有请求的实体类型],
CASE WHEN T1.resource_type = 'OBJECT'
THEN OBJECT_NAME(T1.resource_ASsociated_entity_id)
ELSE T1.resource_type+':'+ISNULL(LTRIM(T1.resource_ASsociated_entity_id),'')
END AS [锁定的对象],
t4.[name] AS [索引],
t1.request_mode AS [锁定类型],
t1.request_session_id AS [当前spid],
t2.blocking_session_id AS [锁定spid],
-- t3.snapshot_isolation_state AS [快照隔离状态],
t3.snapshot_isolation_state_desc AS [快照隔离状态描述],
t3.is_read_committed_snapshot_on AS [已提交读快照隔离]
FROM
sys.dm_tran_locks AS t1
left join
sys.dm_os_waiting_tasks AS t2
ON
t1.lock_owner_address = t2.resource_address
left join
sys.databases AS t3
ON t1.resource_database_id = t3.database_id
left join
(
SELECT rsc_text,rsc_indid,rsc_objid,b.[name]
FROM
sys.syslockinfo a
JOIN
sys.indexes b
ON a.rsc_indid = b.index_id and b.object_id = a.rsc_objid) t4
ON t1.resource_description = t4.rsc_text END
GO
/*
调用示例:exec sp_us_lockinfo
*/
exec sp_us_lockinfo
/*

最后介绍一个隔离等级设置命令:
SET TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED
| READ COMMITTED
| REPEATABLE READ
| SNAPSHOT
| SERIALIZABLE}[;]
该设置的选项将一直对当前连接(数据库连接)始终有效,直到显式更改该选项为止。详情参见。
好,下面开始实例“快乐”之旅了。
五、隔离等级实例
测试数据准备:
CREATE DATABASE testcsdn; GO CREATE TABLE TA(TCID INT PRIMARY KEY,TCNAME VARCHAR(20)) INSERT TA SELECT 1,'AA' INSERT TA SELECT 2,'AA' INSERT TA SELECT 3,'AA' INSERT TA SELECT 4,'BB' INSERT TA SELECT 5,'CC' INSERT TA SELECT 6,'DD' INSERT TA SELECT 7,'DD' GO
1、 未提交读(uncommitted Read)
概念回顾:未提交读是最低等级的隔离,允许其它进程读取本进程未提交的数据行,也就是读取数据时不设置共享锁定直接读取,忽略已经存在的互斥锁定。很显然未提交读这种隔离级别不会造成丢失更新,但是其它意外行为还是可以发生的。它和select 加锁定提示NOLOCK效果相当。
测试实例:
查询一:
SELECT * FROM TA WHERE TCID = 1 BEGIN TRAN UPDATE TA SET TCNAME = 'TA' WHERE TCID = 1 --COMMIT TRAN --Don't commit SELECT * FROM TA WHERE TCID = 1 SELECT @@SPID /* tcid Tcname ----------- -------------------- 1 AA (1 行受影响) (1 行受影响) tcid Tcname ----------- -------------------- 1 TA (1 行受影响) SPID ------ 54 (1 行受影响) */
查询二:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED SELECT * FROM TA WHERE TCID = 1 /* tcid Tcname ----------- -------------------- 1 TA (1 行受影响) */ --显然未提交读模式我们读到SPID=54未提交的数据。
查询三:
SELECT * FROM TA WHERE TCID = 1 --查询一直进行中…… 无结果 --因为缺省下已提交读级别,所以修改数据设置了排它锁定必须等到SPID=54的事务结束
查询四:
exec sp_us_lockinfo

这个时候如果我们回头到查询一里执行commit tran ,你会发现查询三会得到结果,并且是查询一修改后的结果,如果你改用rollback ,那么结果就是原来的值不变,这个你们自己再测试。
2、已提交读(Read Committed)
概念回顾:已提交读是SQL SERVER的缺省隔离级别,悲观模型下是用锁定,乐观模型下使用行版本控制器。这个设置可以通过SET READ_CIMMITTED_SNAPSHOT来修改。在悲观模型下对于读取来说设置共享锁定仅阻止排它锁定,并在数据读取结束自动释放,其它进程方可进行修改操作。也就是说读不会阻止其它进程设置共享及更新锁定,仅阻止排它锁定。在悲观模型下对于修改数据来说设置排锁定阻止所有锁定请示,必须等到排它锁定释放。这个级别的隔离解决了脏读的意外行为。
A、 READ_COMMITTED_SNAPSHOT为OFF的情况(缺省)
I、读数据测试
查询一:
BEGIN TRAN --用锁定提示模拟共享锁定,并强制共享锁定持续到事务结束 SELECT * FROM TA with(holdlock) WHERE TCID = 1 --COMMIT TRAN --Don't commit SELECT @@SPID /* tcid Tcname ----------- -------------------- 1 CA (1 行受影响) ------ 54 (1 行受影响) */
查询二:悲观模型下已提交读级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED UPDATE TA SET TCNAME = 'TA' WHERE TCID = 1 --查询一直没有结果,显然我们验证了共享锁定阻止了排它锁定。
查询三:
exec sp_us_lockinfo --结果大家自己运行看结果。
II、修改数据测试
查询一:
SELECT * FROM TA WHERE TCID = 1 BEGIN TRAN UPDATE TA SET TCNAME = 'READ COMMITTED LOCK' WHERE TCID = 1 --COMMIT TRAN --Don't commit SELECT @@SPID /* tcid Tcname ----------- -------------------- 1 TA (1 行受影响) ------ 54 (1 行受影响) */
查询二:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED SELECT * FROM TA WHERE TCID = 1 /* --查询一直进行中……被锁定无结果 --修改数据设置了排它锁定必须等到SPID=54的事务结束 */
查询三:
exec sp_us_lockinfo

B、 READ_COMMITTED_SNAPSHOT为ON的情况
先修改当前当前库的READ_COMMITTED_SNAPSHOT为ON
ALTER DATABASE TESTCSDN SET READ_COMMITTED_SNAPSHOT ON GO
查询一:
SELECT * FROM TA WHERE TCID = 1 BEGIN TRAN UPDATE TA SET TCNAME = 'READ COMMITTED SNAP' WHERE TCID = 1 --COMMIT TRAN --Don't commit SELECT @@SPID /* TCID TCNAME ----------- -------------------- 1 AA (1 行受影响) (1 行受影响) ------ 56 (1 行受影响) */
查询二:因为启用行版本控制器来锁定数据,保证其它进程读取到虽然被排它锁定但在事务开始前已经提交的保证一致性的数据。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED SELECT * FROM TA WHERE TCID = 1 /* TCID TCNAME ----------- -------------------- 1 AA (1 行受影响) */
查询三:
exec sp_us_lockinfo

SQL2005中的事务与锁定(三)- 转载的更多相关文章
- SQL2005中的事务与锁定(七) - 转载
------------------------------------------------------------------------ -- Author : HappyFlyStone - ...
- SQL2005中的事务与锁定(一) - 转载
----------------------------------------------------------------------- -- Author : HappyFlyStone -- ...
- SQL2005中的事务与锁定(八)- 转载
------------------------------------------------------------------------ -- Author : happyflystone - ...
- SQL2005中的事务与锁定(四)- 转载
------------------------------------------------------------------------ -- Author : HappyFlyStone - ...
- SQL2005中的事务与锁定(二)- 转载
------------------------------------------------------------------------ -- Author : HappyFlyStone ...
- SQL2005中的事务与锁定(九)-(2)- 转载
-------------------------------------------------------------------------- Author : HappyFlyStone -- ...
- SQL2005中的事务与锁定(六) - 转载
------------------------------------------------------------------------ -- Author : HappyFlyStone - ...
- SQL2005中的事务与锁定(五)- 转载
------------------------------------------------------------------------ -- Author : HappyFlyStone - ...
- SQL2005中的事务与锁定(九)- 转载
------------------------------------------------------------------------ -- Author : HappyFlyStone - ...
随机推荐
- Eclispe怎么给工作空间下的项目分组
Eclispe怎么给工作空间下的项目分组 第一步,打开Java Working Set 第二步,添加分组 第三步,选择分组
- NodeJS优缺点及适用场景讨论
概述:NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它有什么优缺点以及它适用于什么场景呢? 本文就个人使用经验对这些问题进行探讨. 一. N ...
- Java面向对象编程
面向对象的软件开发: 面向对象的开发把软件系统看成各种对象的集合,对象就是最小的子系统,一组相关的对象能够组合成复杂的子系统. 面向对象的开发方法具有以下优点: 1.把软件系统看成是各种对象的集合,更 ...
- Linux_磁盘管理
一.linux磁盘管理 命令:fdisk -l brwx-rw--- 其中b(占位符)代表block,块设备文件 sda,sdb... --> 硬盘 其中sda1,sda2..sdb1,sdb2 ...
- MySQL数据库基本数据类型
1.整型 2. 浮点数类型和定点数类型 3.日期与时间类型 4.字符串类型 5. 二进制类型
- c语言中的文件流
一.打开和关闭文件 #include int main( void ) { FILE* pReadFile = fopen( "E:\\mytest.txt", "r&q ...
- iPhone6分辨率与适配
iPhone6分辨率与适配 分辨率和像素 经新xcode6模拟器验证(分辨率为pt,像素为真实pixel): iPhone5分辨率320x568,像素640x1136,@2x iPhone6分辨率37 ...
- JS简单的图片左右滚动
<div id="scroll" style="overflow:hidden;width:757px;"> <table cellpaddi ...
- MySQL Cluster 配置详细介绍
在上篇文章已经详细说明了MySQL Cluster搭建与测试,现在来说说详细的配置参数.在MySQL Cluster 环境的配置文件 config.ini 里面,每一类节点都有两个(或以上)的相应配置 ...
- 关于 calloc 函数使用 与fun 函数
s=(float *) calloc (1,sizeof(float)); #include "stdio.h"#include "stdlib.h"void ...