SQL2005中的事务与锁定(六)

------------------------------------------------------------------------

-- Author : HappyFlyStone

-- Date : 2009-10-12 ――2009-10-17

-- 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

-- 关键字:锁定资源 锁定 应用程序锁定 绑定 锁生命周期 实体类型

------------------------------------------------------------------------

在前面一篇我开始说到锁,然后在说明可锁定资源并没有深入的解释资源这一块,所以没深入是想在大家对锁的模式有一定了解后再来学习资源。在前面的好多用例里我们使用sp_us_lockinf这个用户过程取回的锁的相关信息都有一栏资源类型,呵呵,还有印象吧。下面我们来稍深入理解一下,然后我们对个别类型的资源再来点实例,最后说点锁的本质及生存周期和所有者等等。

4、深入可锁定资源及特殊锁定

可资源资源有哪些呢,我在前面已经用

SELECT * FROM MASTER..SPT_VALUES WHERE TYPE = 'LR'

进行了列表,一共有12种之多,其实我们从本篇的开始到现在一直在接触的行锁(RID),键锁(KEY),分页(PAG)、表(TAB)及对象(OBJECT)都是我们可锁定的资源,这几类我们已经接触到很多了,下面我就不常关注的几个进行一下说明。

EXT 这是数据或索引页面扩展。这一块如果以后有时间整理表的数据存储或索引分页的结构时可以细细说说扩展,现在我们可以简单的理解为:扩展是一个64K的分配单元,是由连续的88K分页组成。SQLSERVER在表或索引分配扩展时会分配8个连续的8K空间,每一个扩展的首页号是8的倍数,但是扩展间本身不一定连续哦,这个不连续就是碎片了。在扩展上也可以加锁定,其实这也好理解,在不同的表或索引需要新的扩展时,系统为了让同一扩展不被错误使用(比如两个表同时得到一个扩展,那比较恐怖哦)而进行共享或排它锁定。不过是系统自发进行的,我们一般看不到。这种物理上的一致性我们在前面提到过一种闩锁,嘿嘿有印象不?我们也可以把这个当作一种事实上的闩锁。

DB数据库(DATABAES)。其实只要我打开一个连接,如果你使用sp_us_lockinfo一定得到一条相应当前连接的DB类型的锁定。结果如图61

select @@spid

go

exec sp_us_lockinfo

那么在DATABASE这种类型下有几种锁呢,为别对应哪些操作呢?能不能模拟出来呢?好,下面我们来模拟一些吧,比如删除库操作

1、 先打开一个managerment studio,我们先创建一个数据库,库名为dblock,建好后运行一下我们前面那个工具sp_us_lockinfo

2、 打开另一个managerment studio,右击dblock进行删除操作,在弹出的窗口点确认

3、 在第二步操作后迅速切换到第一个managerment staido并运行如下代码 ,并得到63

select @@spid

exec sp_us_lockinfo

由上图很明显我们看到我们第一个打开的连接对Dblock有一个DB资源类型的共享锁定排斥了第二个删除操作的排它锁。再比如我们来把Dblock设置成只读,这个更好玩,多了几个锁定哦!先打开两个查询(一定要同时打开两个哦!!)

查询一:

alter database dblock SET READ_ONLY

/*

查询一直进行中……

*/

查询二:(结果图63)

select @@spid

exec sp_us_lockinfo

其它动作大家可以自己模拟

APP应用程序资源。有一个应用程序锁定模式与之对应。应用程序类型的资源锁定与我们前面讨论的所有锁定模式都不一样,前面所有的锁定全是SQLSERVER自己管理的,应用程序级锁定利用了SQLSERVER的检测阻塞及死锁的机制来锁定自己想要锁定的任何对象。比如我们现在想要达到这一种效果:一个表或过程同时只有一个进程能够运行。为了来模拟这种类型的锁定,先看如下语法:

sp_getapplock [ @Resource = ] 'resource_name', 
[ @LockMode = ] 'lock_mode' 
[ , [ @LockOwner = ] 'lock_owner' ] 
[ , [ @LockTimeout = ] 'value' ]
[ , [ @DbPrincipal = ] 'database_principal' ]

[ ; ]

下面我们来模拟一下:

查询一:

exec sp_getapplock 'testapplock','exclusive','session';

go

select * from ta

--sp_releaseapplock 'testapplock','session';

查询二:

exec sp_getapplock 'testapplock','exclusive','session';

go

select * from ta

/*

查询一直进行中。。。。。。

*/

查询三:结果图64

--create database dblock

select @@spid

exec sp_us_lockinfo

METADATA 元数据。这种类型的可锁定资源我们其实前面已经有看过,我们在修改当前库为只读时,看如图65

好,到目前为止对可锁定的资源就说完了。嘿嘿,另外几个比如堆或B树类型锁定(HBT)不如以后整理索引时再旧事重提了。

5、锁的本质、生命周期及请求锁定的实体类型

首先我告诉大家SQLSERVER并不知道(或不关心)被它锁定的对象,有时即使我们能关联到对象却无法正确解析被锁定对象的结构,你相信吗?猛一听有点吓人吧,这么重要的任务交给它管理,它不知道被管理的东西是何方神圣?呵呵,下面稍稍说一点内部的结构。

锁是SQLSERVER的一种内存结构,并不是一种物理的数据结构,所以这种元数据追踪是无法被记录的。关闭或中止一个连接相应的部分锁定信息就会消失。这个结构书上都称锁块(Lock block),用这个锁块来跟踪数据、锁定及对锁相关的信息描述。显然这些锁块是要被不同进程所拥有的,SQL有另一个叫所有者块来管理这些,所有者块与锁块之间通过所有者的指针相连。

在锁块里有一个专门对锁定资源的描述结构叫资源块,资源块负责维护资源名称、锁块的指针、已经授权的所有者指针列表、转换中的所有者指针列表、等待的所有者列表。对资源块有一个类型描述,占用一个字节,这个类型描述我在前面已经通过SQL语句进行列表过:

查询一:

SELECT *

FROM MASTER..SPT_VALUES WHERE TYPE = 'LR'

对具体的资源描述有12个字节的内存结构来记录。我们在2000下使用过一个表syslockinfo,这些信息在rsc_bin中有体现,这个字段对资源进行描述,根据类型的不同,这12个字节有着不同的分工组合。在这里我还要提醒2000下的用户,rsc_bin2005里意义不再等同于2000,但是仅是微小的差别。为了说明我上面的论点,所以对syslockinfo进行一下深入,证明SQLSERVER对被的对象是不关心的。我们先来实际看看这个表的数据,结果集如图66

通过这个图我们应该看到rsc_bin的最两个字节和2000下不一样了,这两个字节交换后就是资源块的类型,这一点大家要注意哦。

Query 1:

CREATE TABLE TB (ID INT primary key, COL VARCHAR(16))

GO

INSERT INTO TB SELECT 1,'A'

GO

SET TRANSACTION ISOLATION LEVEL repeatable read

BEGIN TRAN

SELECT * FROM TB WHERE id BETWEEN 1 AND 5

  对上图我们很容易理解类型为objecpagersc_bin意义。重点说一下KEY类型的共享锁定。这一条记录在syslockinforsc_bin列,前6个字节是分区ID,我们可以通过sys.partitions查找到相应的分区。紧接着的6个字节(上图用红粗线标识的部分)来头不小,是根据当前索引的所有索引列生成的中介现象哈希值,在这里对这个哈希会值是无法反推的。如果上面的表及页面我们可以查找到相应的结构的话,那个对这个键值锁定真的就是不是不想知道结构,而是真的不知道什么结构了哈。哈哈,这儿证明我上面的结论吧。其实我们不用担心,因为虽然不能反推,但是阻塞或死锁机制是还是可以查找匹配的呀,也就是如果相同时生成的哈希一样,那样SQLSERVER还知道这是相同听资源,阻塞或死锁已经发生。嘿嘿,其实只要关心被它锁定资源的标识串就足以管理阻塞或死锁,

  请求锁定的实体类型,这个在前面的几乎每一个图表里都可以看到的一列。图68

在这个图里我们只看到两类,还有另外两类,一共四类:事务类型,游标类型、事务工作空间类型、会话类型

  事务类型:这个就不用多说了吧,上面我们显式的开始一个事务时,此连接都会有一个事务类型的实体。

  事务工作空间类型:这是SQLSERVER2005引入的。SQLSERVER2000把所有除事务与游标类型的实体全归为会话型。通常我们看到的数据库级锁定就是空间类型的,也就是基本一个会话就对应一个工作空间,这样会话中所有的数据库级锁定会保留在相同的工作空间里,这对于绑定会话是有十分重要的意义。

就绑定来说MS明确会在以后的版本不支持了。因为我们在以前版本用过,所以这儿稍微说说。

先说说绑定出现的背景吧,首先明确一点锁定的阻塞是发生在不同的SQL进程间,也就是进程自己是不会把自己锁起来的。接着再明确一点何为相同进程,每一个独立的SQL连接,但是我们不要错误的认为同一个用户同一个程序就一定一个连接、一个进程。事实上同一个用户同一个应用程序拥有多个连接即进程的可能程是非常大的。那么我们显然就可以想像到同一个用户同一个程序自己可能锁定自己,因为它拥有多个连接是吧,而SQLSERVER是无法知道同一应用程序拥有哪几个连接,也不知道这些连接间怎么关联的。那么这个问题怎么解决呢。在SQL6.5以后SQL2005以前就是用绑字,当然2005也支持,但是MS明确在以后的版本可能不支持了。

绑定分为本地绑字及分布式绑定,它完成不同连接在同一事务空间内的交互或不同服务器上工作单元的交互。一般绑它以第一个连接进行连接并申请“绑定令牌”,这个令牌就是一个事务空间的变量字符串,这个变量字符串可供后续的连接进行检索,并且这个变量串对应的事务空间就会被共享。

下面简单的做一个测试吧!

查询一:

begin tran

declare @token varchar(100)

exec sp_getbindtoken @token output

select @token

select * from tb

update tb

set col = 'b'

where id = 1

/*

-------------------------

.Y4bBahH9aCGCj[a[0b-:-5---03E=--

(1 行受影响)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值