日期:2014-05-17  浏览次数:20443 次

求教sqlserver 关于锁的问题
1.请问如果开启一个事务,往一个表里插入一条数据,在事务提交之前,是否整个表都被排它锁锁住?其他的事务无法select?我觉得应该只锁插入的那一条吧,只要select没去输出新插入的那条未提交的数据是可以查询的,可是实测的情况是,整个表都不允许查询。
2.如果开启一个事务select一个表的全部数据,在事务提交之前,是否整个表都会被共享锁锁住?在这种情况下,开启一个新事务,向表里插入数据可以吗?我觉得是不可以的,可是测试的时候发现是可以的。
求大神解疑

------解决方案--------------------
1. 你说对了一办,自己插入的那一行是X锁,不提交就不释放,同事在表和页上还有个IX锁,表示这个表和页正在被修改中,IX和S锁不兼容的,也就是说,其他人的select表/页也是会等待的;

2. 这个要看你的隔离级别了,select是S锁,在read committed(默认的隔离级别)下用完会自动释放的,所以可以插入数据的。
开启repeatable read隔离级别会保持住S锁不释放,其他人无法修改被查询的数据,但是任然可以插入。
想要不能插入,需要开启serializable隔离级别。

------解决方案--------------------
测试脚本:
USE tempdb
GO
CREATE TABLE [dbo].[TableLOCK](
[ID] [nchar](10) NOT NULL,
[CL2] [nchar](10) NULL
 )
 GO

 INSERT INTO [dbo].[TableLOCK] VALUES('B','B1')
 INSERT INTO [dbo].[TableLOCK] VALUES('C','C1')
 INSERT INTO [dbo].[TableLOCK] VALUES('D','D1')
 INSERT INTO [dbo].[TableLOCK] VALUES('E','E1')
 GO
Session1 
BEGIN TRAN
INSERT INTO [dbo].[TableLOCK] VALUES('A','A1')

 然后去查LOCKS的情况
SELECT * FROM [sys].[dm_tran_locks] where [resource_database_id]=2
结果是有一条 MODE为 X 的RID 锁。

Session2 
例子1,运行 SELECT * FROM [dbo].[TableLOCK] ,
被阻塞,很明显嘛, 上面的语句要获取Session1的排他RID嘛,这样也可以从[dm_tran_locks] 从查到。

例子2,运行SELECT top 1 * FROM [dbo].[TableLOCK] 
查看计划,是表扫描,可是没有阻塞。为什么??? 很明显嘛,表扫描的第一条记录是什么?是VALUES('B','B1') 嘛,很明显VALUES('B','B1') 没有任何锁,所以当然不会阻塞,获取之后上面的语句马上退出,不会继续扫描了,所以不会阻塞。

例子3, Session1 的语句改为
BEGIN TRAN
Update [dbo].[TableLOCK] Set [ID]='A' where [ID]='B'

再次在Session2里 运行SELECT top 1 * FROM [dbo].[TableLOCK] 
这次缺被阻塞了。为什么?很明显嘛,这次表扫描的第一条记录还是VALUES('B','B1')嘛,但是这次VALUES('B','B1') 已经在Session1中没上了排它锁。

未完待续。
------解决方案--------------------
你的回复终于让我可以说话了(连续3个回复之后不能再回复了?这TMD的谁设计的?),你的问题正是我想要说的。
现在看where的情况,
Session1 
BEGIN TRAN
INSERT INTO [dbo].[TableLOCK] VALUES('A','A1')

例子4,Session2
SELECT * FROM [dbo].[TableLOCK] where ID='B'
被阻塞,很明显的,计划是表扫描,原因跟例子1相同,既然表扫描,那就要访问VALUES('A','A1')

例子5, SELECT  * FROM [dbo].[TableLOCK]   WHERE [CL2]='B1'
被阻塞,很明显的,计划还是表扫描,原因跟例子1相同,既然表扫描,那就要访问VALUES('A','A1')
,而VALUES('A','A1')已经上了排它锁。

例子6,对TableLOCK创建NONCLUSTERED INDEX
CREATE NONCLUSTERED INDEX [NCI1] ON [dbo].[TableLOCK]
([CL2] ASC) 
然后运行例子5,还是被阻塞,为什么? 原因跟例子3一样。

例子7。那上面的语句可以让它不阻塞吗?当然似乎,是可以的。
SELECT  * FROM [dbo].[TableLOCK]  WITH (INDEX([NCI1]))  WHERE [CL2]='B1'
计划变成INDEX SEEK了嘛,这个时候,index的KEY跟对应的RID都没有锁,自然就不锁了。

还没完,待续??? 
先这样吧,看看反应再说
------解决方案--------------------
当操作某表达一条数据时,其它的事务能否更新此表的数据,取决于是否有表级锁。
而是否会产生表级锁,和在你的查询条件中的查询字段是否为唯一索引(如主键)是相关的;