UPDLOCK 的优点是允许您读取数据(不阻塞其它事务)并在以后更新数据,同时确保自从上次读取数据后数据没有被更改。当我们用UPDLOCK来读取记录时可以对取到的记录加上更新锁,从而加上锁的记录在其它的线程中是不能更改的只能等本线程的事务结束后才能更改。
感觉描述不是很完整?
直接上测试吧,这是我的测试表。
1,先来测试UPDLOCK对其它事务CURD的影响。
新建查询窗口1,并执行语句。
begin tran if((select NickName from Users with(updlock) where id=2004)='ttt') begin waitfor delay '0:0:5' print('等下要做其它示例') end commit tran
新建查询窗口2,并执行语句。(waifor结束之前)
insert into Users(NickName,Sex,RegisterTime) values('uuu',1,getdate()) --结论:不堵塞,窗口1事务还没执行完就可以insert(重复上面的步骤分别执行下列语句) update Users set Sex=-1 where id=3004 --结论:不堵塞 update Users set Sex=-1 where id=2004 --结论:堵塞,必须等到窗口1事务执行完。因为窗口1锁了2004这一行,说明锁的粒度不设置则默认是行锁? select * from Users where id=2004 select * from Users --结论:不堵塞。 delete from Users where id=2004 --结论:堵塞。
2,两个updlock事务相遇
稍微修改事务1
begin tran if((select NickName from Users with(updlock) where id=2004)='ttt') begin waitfor delay '0:0:5' update Users set NickName='sss',Sex=Sex+1 where id=2004 end commit tran
然后把事务1复制到窗口2,模拟事务并发。
先执行窗口1,立马执行窗口2,窗口2执行到第二行就会等待。从下图结果就可以看出窗口2的第二行并没有通过,所以没有后续的update
并没有产生并发问题,按第一段的描述应该认为updlock会使其它事务可以读取锁定行,但是不能修改。
还搜了tablockx排它锁的描述(基本都差不多):
此选项被选中时,SQL Server 将在整个表上置排它锁直至该命令或事务结束。这将防止其他进程读取或修改表中的数据。
窗口1
begin tran if((select NickName from Users with(TABLOCKX) where id=2004)='ttt') begin waitfor delay '0:0:5' update Users set NickName='sss',Sex=Sex+1 where id=2004 end commit tran
窗口2
select * from Users where id=2004
窗口2不会被堵塞,“这将防止其他进程读取或修改表中的数据”,虽然我不太懂这里所说的“进程”是什么意思,试试用另一台机器执行窗口2,在虚拟机下连接数据库执行窗口2语句,结果确实是堵塞了。ps:其实不光其它进程不能修改表中数据,同一进程下也不能修改。
所以网上这些的描述都很乱?哪里能找到这方面的比较详细比较权威的文档?
我感觉(不一定正确),updlock锁会申请U锁,而这里updlock一般会在查询后同事务内进行更新,这个时候就转为X锁,而在两个U锁(你的两个updlock)时是冲突的(这个你可以在网上找下锁的兼容表,U和S是兼容的)。这个updlock和update语句执行时候过程一致,只是update由S锁转X锁很快所以基本可以认为就是X锁。
另一个是不是行锁这个不是你说的算的,锁的粒度和很多东西相关,如果表没索引的话估计就转成表锁,而有些时候会针对索引加锁,如果你是范围查询这个时候可能锁的就是页了。。。。这个太杂了,不是一下能说的清楚(我也是一知半解)
看这些东西最好直接去msdn翻吧,网上中文网站都是你拷我我拷你,技术水平参差不齐,很容易带到坑里,而且msdn最好看英文版的,中文版有些地方用词也有问题。