锁不住的查询

系统 1521 0

环境: SQL Server 2005 or 2008

最近在处理一个锁的问题时,发现一个比较郁闷的事,使用 X 锁居然无法锁住查询,模拟这个问题,可以使用如下 T-SQL 脚本来建立测试环境。

USE master ;

GO

IF @@TRANCOUNT > 0

ROLLBACK TRAN ;

GO

-- =======================================

-- 建立测试数据库

-- a. 删除测试库 , 如果已经存在的话

IF DB_ID ( N'db_xlock_test' ) IS NOT NULL

BEGIN ;

ALTER DATABASE db_xlock_test

SET SINGLE_USER

WITH

ROLLBACK AFTER 0 ;

DROP DATABASE db_xlock_test ;

END ;

-- b. 建立测试数据库

CREATE DATABASE db_xlock_test ;

-- c. 关闭 READ_COMMITTED_SNAPSHOT 以保持 SELECT 的默认加锁模式

ALTER DATABASE db_xlock_test

SET READ_COMMITTED_SNAPSHOT OFF ;

GO

-- =======================================

-- 建立测试表

USE db_xlock_test ;

GO

CREATE TABLE dbo . tb (

id int IDENTITY

PRIMARY KEY ,

name sysname

);

INSERT dbo . tb

SELECT TOP ( 50000 )

O1 . name + N'.' + O2 . name + N'.' + O3 . name

FROM sys . objects O1 WITH ( NOLOCK ),

sys . objects O2 WITH ( NOLOCK ),

sys . objects O3 WITH ( NOLOCK );

GO

然后,建立一个连接,执行下面的脚本来实现加锁。

-- =======================================

-- 测试连接 1 - 加锁

BEGIN TRAN

-- 测试的初衷是通过 SELECT 加锁,结果发现 UPDATE 也锁不住

UPDATE dbo . tb SET name = name

--SELECT COUNT(*) FROM dbo.tb WITH(XLOCK)

WHERE id <= 2 ;

SELECT

spid = @@SPID ,

tran_count = @@TRANCOUNT ,

database_name = DB_NAME (),

object_id = OBJECT_ID ( N'dbo.tb' , N'Table' );

-- 显示锁

EXEC sp_lock @@SPID ;

通过执行结果,可以看到对象被加锁的情况:表级和页级上是 IX 锁,记录上是 X 锁。

spid

tran_count

database_name

object_id

51

1

db_xlock_test

21575115

spid

dbid

ObjId

IndId

Type

Resource

Mode

Status

51

7

0

0

DB

S

GRANT

51

7

21575115

1

PAG

0.095138889

IX

GRANT

51

7

21575115

0

TAB

IX

GRANT

51

1

1131151075

0

TAB

IS

GRANT

51

7

21575115

1

KEY

(020068e8b274)

X

GRANT

51

7

21575115

1

KEY

-10086470766

X

GRANT

然后新建一个连接,执行下面的 T-SQL 查询,看看会否被连接 1 锁住

-- =======================================

-- 测试连接 2 - 被阻塞 ( 在测试连接 1 执行后执行 )

SET TRANSACTION ISOLATION LEVEL READ COMMITTED ;

SELECT * FROM dbo . tb

WHERE id <= 2 ;

上述查询会很快返回结果,并不会被查询 1 阻塞住。

按照我们的了解(联机帮助上也有说明),在 READ COMMITTED 事务隔离级别下,查询使用共享锁( S ),而根据锁的兼容级别, S 锁是与 X 锁冲突的,所以正常情况下,连接 2 的查询需要等待连接 1 执行完成。可是测试的结果去违反了这一原则。

为了了解为什么连接 2 不会被阻塞,对连接 2 做了一个 Trace ,发现一个更郁闷的问题, Trace 的结果如下:

EventClass

TextData

ObjectID

Type

Mode

Lock:Acquired

21575115

5 - OBJECT

6 - IS

Lock:Acquired

1:77

0

6 - PAGE

6 - IS

Lock:Acquired

[PLANGUIDE]

0

2 - DATABASE

3 - S

Lock:Acquired

21575115

5 - OBJECT

6 - IS

Lock:Acquired

1:77

0

6 - PAGE

6 - IS

Lock:Acquired

1:80

0

6 - PAGE

6 - IS

Lock:Acquired

width
分享到:
评论
wsql
  • 浏览: 2218460 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最新评论

锁不住的查询


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论