CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  MS-SQL Server >  疑难问题

sql server 更新表数据时,会给表加排他锁,如何解除排他锁

楼主jupiterhunter(木猎)2006-06-28 17:01:37 在 MS-SQL Server / 疑难问题 提问

当sql   server   ,更新一个表时,此时   sql   server会给   表加一个排他锁,但是其他用户要更新时,却不得不等第一个用户更新完,才能更新,如何解除   排他锁,禁止sql   server自动给这个表加排他锁 问题点数:100、回复次数:27Top

1 楼fengfangfang()回复于 2006-06-28 17:04:04 得分 0

不可以Top

2 楼LouisXIV(夜游神)回复于 2006-06-28 17:15:48 得分 0

lz的想法会造成问题的^^Top

3 楼zjcxc(邹建)回复于 2006-06-28 20:28:21 得分 60

不可能实现.Top

4 楼zjcxc(邹建)回复于 2006-06-28 20:30:14 得分 0

不加锁的话,   两个用户同时更新一条记录,   那数据库中保存的应该是那个用户的记录呢?    
  如果只能保存一个用户的数据,   那么返回信息的时候,   得给一个用户失败的错误信息,   那这样还不如加锁让一个用户等待?  
  如果两个用户都返回成功的信息,   那更不对了,   明明只保存了一个用户的数据嘛.Top

5 楼suntt(两条腿的狗)回复于 2006-06-28 20:59:40 得分 0

你只能想办法降低锁的粒度,尽量将在表上排他锁降低到页或行级别Top

6 楼LouisXIV(夜游神)回复于 2006-06-28 21:09:52 得分 0

^^  
   
  老大说的浅显易懂Top

7 楼li_zero(相遇太早,反而淡了缘分)回复于 2006-06-28 22:01:12 得分 0

可以更改,参见SET   TRANSACTION   ISOLATION   LEVEL,不过从数据角度来考虑,这个很不建议使用。  
   
  事务必须运行于可重复读或更高的隔离级别以防止丢失更新。当两个事务检索相同的行,然后基于原检索的值对行进行更新时,会发生丢失更新。如果两个事务使用一个   UPDATE   语句更新行,并且不基于以前检索的值进行更新,则在默认的提交读隔离级别不会发生丢失更新。  
   
  Top

8 楼lzhs(快乐至上)回复于 2006-06-29 10:56:22 得分 40

可以更改,参见SET   TRANSACTION   ISOLATION   LEVEL,不过从数据角度来考虑,这个很不建议使用。  
  ==========================================  
  不可以的。  
   
  Begin   Tran    
  Set   Transaction   Isolation   Level   READ   UNCOMMITTED  
  Update   BuildInfo   Set   Floors   =   6   Where   Num   =   'A'  
  --执行到这儿停,不提交事务  
  Commit   Tran  
   
   
  在另外一个Conn中执行  
  Update   BuildInfo  
  Set   Floors   =   5  
  Where   Num   =   'A'  
  会进入等待的,直到上面Commit   Tran之后,才会执行完成。  
   
   
   
   
   
  Top

9 楼li_zero(相遇太早,反而淡了缘分)回复于 2006-06-29 11:34:26 得分 0

楼上的你写错了吧,Set   Transaction   Isolation   Level   READ   UNCOMMITTED   要对每个连接执行,并且要再begin   tran之前执行,我试过的。Top

10 楼lzhs(快乐至上)回复于 2006-06-29 16:25:53 得分 0

。。。  
  Set   就算是写在之前也不行的。  
  Top

11 楼zjcxc(邹建)回复于 2006-06-29 19:39:53 得分 0

TO:   li_zero(相遇太早,缘分太浅)    
   
  你说的和楼主要的不是同一个东西  
   
   
  READ   UNCOMMITTED  
  指定语句可以读取已由其他事务修改但尚未提交的行。  
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==   这个是最低的事务隔离级别  
                          ^^^^   看见了吗,   这里是读取,   而楼主要的是更新不加锁  
   
   
  在   READ   UNCOMMITTED   级别运行的事务,不会发出共享锁来防止其他事务修改当前事务读取的数据。READ   UNCOMMITTED   事务也不会被排他锁阻塞,排他锁会禁止当前事务读取其他事务已修改但尚未提交的行。设置此选项之后,可以读取未提交的修改,这种读取称为脏读。在事务结束之前,可以更改数据中的值,行也可以出现在数据集中或从数据集中消失。该选项的作用与在事务内所有   SELECT   语句中的所有表上设置   NOLOCK   相同。这是隔离级别中限制最少的级别。  
   
   
  Top

12 楼zjcxc(邹建)回复于 2006-06-29 19:43:49 得分 0

简单地说,   READ   UNCOMMITTED   更改的是   SELECT   加锁的行为,   即不让   SELECT   加锁  
   
  SQL通过锁之间的相容或者相斥来实现那些操作与那些操作能或者不能同时进行.  
   
  而   READ   UNCOMMITTED   让   SELECT   不加锁,   既然没有锁,   当然不会产生与其他锁是否相容或者相斥的问题,   从而跳过了   update   下的排它锁  
   
  但它并不会让   update   不下排它锁Top

13 楼zjcxc(邹建)回复于 2006-06-29 19:51:54 得分 0

--   可以用下面的代码来测试,   说明   UPDATE   加的排它锁  
   
  --   窗口1执行下面的代码  
  CREATE   TABLE   dbo.tb(id   int)  
  INSERT   dbo.tb   SELECT   id   FROM   sysobjects  
  GO  
   
  SET   TRANSACTION   ISOLATION   LEVEL   READ   UNCOMMITTED  
  BEGIN   TRAN  
  UPDATE   dbo.tb   SET   id   =   id   +   2  
  WHERE   id   <100  
  --   ROLLBACK   TRAN     --   让事务保持  
  GO  
   
   
   
   
  --   查询窗口2执行下面的语句  
  SET   TRANSACTION   ISOLATION   LEVEL   READ   UNCOMMITTED  
  BEGIN   TRAN  
  UPDATE   dbo.tb   SET   id   =   id   +   2  
  WHERE   id   <100  
  ROLLBACK   TRAN     --   让事务保持  
   
   
  --   测试说明:   如果查询窗口2的语句能立即执行完成,   说明   READ   UNCOMMITTED   确实去掉了UPDATE的   X   锁.Top

14 楼lzhs(快乐至上)回复于 2006-06-30 09:44:04 得分 0

还可以这样验证,执行下面的语句:  
  Set   Transaction   Isolation   Level   READ   UNCOMMITTED  
  Begin   Tran    
  Update   BuildInfo   Set   Floors   =   6   Where   Num   =   'A'  
   
  然后  
  执行sp_lock,结果如下:  
  51 8 0 0 DB                                 S GRANT  
  51 8 453576654 1 PAG 1:41                         IX GRANT  
  51 1 85575343 0 TAB                                 Sch-S GRANT  
  51 8 453576654 0 TAB                                 IX GRANT  
  51 8 453576654 1 KEY (41007461262c)     X GRANT  
  52 8 0 0 DB                                 S GRANT  
   
  执行select   object_name(453576654),结果如下:  
  BuildInfo  
   
  可见,就算你指定了Transaction   Isolation   Level为Read   Uncommitted,Update语句还是会给要Update的对象加上X锁(排它锁)的。  
   
  最后commit   tran   或rollback   tran,就会发现这个X锁没有了。  
   
  Top

15 楼jupiterhunter(木猎)回复于 2006-06-30 15:30:21 得分 0

感谢各位的积极留言,我的问题难道走到死胡同了吗?  
   
  我遇到的问题,我写了一个存储过程,6个用户同时更新 一个表的内容,并且是各自更新各自的数据,互不干扰,比如  
   
  第1个用户 update   表1 set   字段1='1'   where   flag=1  
  第2个用户 update   表1 set   字段1='1'   where   flag=2  
  第3个用户 update   表1 set   字段1='1'   where   flag=3  
   
  当第一个用户执行时,第二个用户和第三个用户都要等待,怎么才能 让三个用户同时执行,提高速度和效率,难道真的要把 表1,分成多个表?  
  Top

16 楼lzhs(快乐至上)回复于 2006-06-30 17:36:52 得分 0

第1个用户 update   表1 set   字段1='1'   where   flag=1  
  第2个用户 update   表1 set   字段1='1'   where   flag=2  
  第3个用户 update   表1 set   字段1='1'   where   flag=3  
  ======================================================  
  这些语句不会造成等待吧?  
  Top

17 楼zjcxc(邹建)回复于 2006-06-30 20:55:38 得分 0

这个难说,   如果   update   的条件不必扫描被锁定的资源,   就可以定位到所有满足条件的记录,   那自然就不会被锁住.  
   
  否则当然会被锁住.Top

18 楼zjcxc(邹建)回复于 2006-06-30 20:58:26 得分 0

还是有示例比较能说明问题:  
   
  --   1.   创建测试环境  
  CREATE   TABLE   dbo.tb(  
  id   int   IDENTITY(1,   1),    
  flag   int,  
  col   int)  
  INSERT   dbo.tb(flag,   col)  
  SELECT   1,   1   UNION   ALL  
  SELECT   2,   1   UNION   ALL  
  SELECT   3,   1  
  GO  
   
  ALTER   TABLE   dbo.tb   ADD   PRIMARY   KEY(id)  
  CREATE   INDEX   IX_flag   ON   dbo.tb(flag)  
  GO  
   
  --DROP   TABLE   dbo.tbTop

19 楼zjcxc(邹建)回复于 2006-06-30 20:59:15 得分 0

--   查询窗口1     中执行下面的查询  
  BEGIN   TRAN  
  UPDATE   dbo.tb   SET   col   =   col   +   1  
  WHERE   flag     =   1  
  --ROLLBACK   TRAN   --   让事务一直保持,   以保持对数据下的锁Top

20 楼zjcxc(邹建)回复于 2006-06-30 20:59:41 得分 0

--   查询窗口2     中执行下面的查询  
   
  BEGIN   TRAN  
  UPDATE   A   SET   col   =   col   +   1  
  FROM   dbo.tb   A    
  -- WITH(INDEX   =   IX_flag)  
  WHERE   flag   =   2  
  ROLLBACK   TRAN  
  Top

21 楼zjcxc(邹建)回复于 2006-06-30 21:03:33 得分 0

结果:  
  你会发现查询窗口2的处理被BLOCK了,   原因是默认情况下,   sql直接走聚集索引(这里是主键)来扫描数据,   而要通过   flag   来定位数据的话,   要扫描全部的聚集索引,   也就是要扫描到查询窗口1中加锁的资源了  
   
   
  终止查询窗口2中的查询,   去掉我加的注释,   让   WITH(INDEX   =   IX_flag)   生效,   再执行查询,   你会发现处理很快执行完成.  
   
  原因:  
  我们指定了   WITH   选项后,   ``强制sql走   IX_flag   查询,   由于   IX_flag   索引并没有持有任何锁资源,   因此在这个索引上能定位到满足条件的记录,   而这个满足条件的记录对应的原始资源并未被锁定,   所以更新得以顺利进行.Top

22 楼lzhs(快乐至上)回复于 2006-07-01 10:31:16 得分 0

我昨天在我的机器上也做过这样的试验:  
  查询一:  
  BEGIN   TRAN  
  UPDATE   dbo.tb   SET   col   =   col   +   1  
  WHERE   flag     =   1  
   
  查询二:  
  UPDATE   dbo.tb   SET   col   =   col   +   1  
  WHERE   flag     =   2  
   
  即使flag为主键的话,查询二也能执行的。  
  但如果换成:  
  UPDATE   dbo.tb   SET   col   =   col   +   1  
  WHERE   flag     <>   1  
  那就不行了,就进入了等待状态。  
   
  Top

23 楼lzhs(快乐至上)回复于 2006-07-01 10:34:44 得分 0

你会发现查询窗口2的处理被BLOCK了,   原因是默认情况下,   sql直接走聚集索引(这里是主键)来扫描数据,   而要通过   flag   来定位数据的话,   要扫描全部的聚集索引,   也就是要扫描到查询窗口1中加锁的资源了  
  ==========================  
  我觉得这儿有不当的地方,如果用聚集索引的话,应该能够直接定位到flag   =   1   或2的情况,不会扫描(flag   =   其他)的部分吧?  
   
  我现在没有实验环境,等周一再试验一下吧。  
   
   
  Top

24 楼zjcxc(邹建)回复于 2006-07-01 19:56:25 得分 0

主键并没有flag列,   所以不扫描表那能够判断flag值?Top

25 楼zjcxc(邹建)回复于 2006-07-01 20:01:33 得分 0

至于查询走不走主键,   这个是通过查询计划来看的  
   
  不同的表结构和不同的数据,   会让同一个处理语句的执行计划不同,   所以换语句,   或者换数据,   都可能不走主键.  
   
  而我要说明的,   只是说更新的扫描,   如果不扫描到被锁定的资源,   就不会被堵塞.  
  (我的例子只是来说明这一点)Top

26 楼lzhs(快乐至上)回复于 2006-07-01 20:46:00 得分 0

。。。  
  不好意思,早上那会刚起来,没看清楚。你的主键是建在id上,不是flag上的。  
  你的说法是正确的。  
  :)  
   
  我觉得可以有一个折衷的方法,就是建一个可更新的视图:  
  Create   View   vTest  
  As  
  Select   *   From   tb   With(ReadPast)    
  --视图定义查询使用ReadPast,不读取被锁定的列,这样的话,直接更新视图就可以了。  
   
  更新的时候,更新这个视图:  
  查询一:  
  BEGIN   TRAN  
  UPDATE   vTest   Set   col   =   col   +   1  
  WHERE   flag     =   1  
   
  查询二:  
  BEGIN   TRAN  
  UPDATE   vTest   SET   col   =   col   +   1  
  WHERE   flag     =   2  
  Top

27 楼seayar(习习)回复于 2006-07-26 10:00:28 得分 0

学习Top

相关问题

关键词

得分解答快速导航

  • 帖主:jupiterhunter
  • zjcxc
  • lzhs

相关链接

  • SQL Server类图书

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo