一次意外的X锁不阻塞问题
最近有一个朋友问我一个关于给查询操作强制上X锁却不阻塞的问题。该查询写在一个存储过程中,代码如代码1所示:
1: create PROC [dbo].[GetCityOrders]
2: @city NVARCHAR(10) ,
3: @num INT
4: AS
5: SET NOCOUNT ON
6:
7: BEGIN TRY
8:
9: BEGIN TRAN
10:
11: SELECT TOP ( @num )
12: id ,
13: number ,
14: price ,
15: mid ,
16: @city city
17: INTO #cityorders
18: FROM cmcc WITH ( XLOCK )
19: WHERE prov = 0
20: AND status = 0
21: AND city = @city
22:
23: UPDATE cmcc
24: SET status = 100
25: WHERE id IN ( SELECT id
26: FROM #cityorders )
27:
28: SELECT o.* ,
29: c.attach
30: FROM #cityorders o
31: LEFT JOIN cmcc_attach c ON o.id = c.id
32:
33: DROP TABLE #cityorders
34:
35: COMMIT TRAN
36:
37: END TRY
38: BEGIN CATCH
39:
40: ROLLBACK
41:
42: END CATCH
代码1.
该存储过程首先通过对查询操作加X锁,使得其他读取操作更新时不影响该部分加X锁的操作。乍一看没有任何问题,但是当业务上线后就发现,即使查询有了X锁,但实际上还是会有多个调用该存储过程的客户端同时读取到同一条数据的现象现象。
原因?
为了验证原因,我们来做一个Demo测试,首先我们创建测试表,代码如代码2所示。
1: CREATE TABLE dbo.DemoX
2: (
3: [key] INT PRIMARY KEY ,
4: [value] INT,
5: );
6: GO
7: INSERT INTO dbo.DemoX
8: ( [key], value )
9: VALUES ( 1, 100 );
10: GO
代码2.创建测试DEMO
接下来,对该DemoX表进行Select操作,并查看锁。如代码3所示。
1: BEGIN TRAN
2: SELECT [key],value
3: FROM dbo.DemoX D WITH (XLOCK);
4:
5: SELECT L.resource_type,
6: L.request_mode,
7: L.request_status,
8: L.resource_description,
9: L.resource_associated_entity_id
10: FROM sys.dm_tran_current_transaction T
11: JOIN sys.dm_tran_locks L
12: ON L.request_owner_id = T.transaction_id;
代码3.使用X锁提示查语句
在代码3中显式指定了X锁,并查看上锁情况,可以看出X锁以及对应父对象上的意向锁都正常存在,如图1所示。

图1.
我们再开另外一个窗口运行一个普通的Select,结果如图2所示。

图2.
为什么没有阻塞
理论上来说,第二个查询应该会被阻塞,因为第二个查询所需加的S锁和第一个查询的X锁不兼容。后来在网上找打StackOverFlow的一篇博文:“http://stackoverflow.com/questions/4609217/sql-server-the-misleading-xlock-optimizations”,找到了答案。
在SQL Server中,默认的已提交读为了保证不读脏数据(既在内存中修改,还未落盘的数据),会对需要查找的数据上S锁,但如果发现数据并不是脏数据,则会优化跳过加S锁的步骤,代码3中的查询语句强制使用了X锁提示,但未进行任何数据修改,所以不存在脏数据,因此后续查询就通过优化放弃使用S锁,从而不阻塞,导致了意料之外的结果。
解决办法
SQL Server对于该特性的优化仅仅对行锁生效,如果在指定查询时使用页锁提示,则会按照语句,对阻塞后续查询,代码如代码4所示。
1: SELECT [key],value
2: FROM dbo.DemoX D WITH (PAGLOCK,XLOCK);
代码4.
但显而易见,该方法会降低并发,如果有可能,请不要对Select操作使用X锁提示,否则请加上页锁提示。
另一个办法是使用CTE进行表更新,将代码1中的代码两部分合二为一,数据在更新时会导致脏数据,因此不会出现跳过S锁的情况。
一次意外的X锁不阻塞问题的更多相关文章
- PHP自带Session隐患(session文件独占锁引起阻塞)
PHP自带Session隐患(session文件独占锁引起阻塞) PHP默认的会话处理器是session.save_handler = files(即文件).如果同一个客户端同时并发发送多个请求(如a ...
- 第十六章——处理锁、阻塞和死锁(3)——使用SQLServer Profiler侦测死锁
原文:第十六章--处理锁.阻塞和死锁(3)--使用SQLServer Profiler侦测死锁 前言: 作为DBA,可能经常会遇到有同事或者客户反映经常发生死锁,影响了系统的使用.此时,你需要尽快侦测 ...
- 使用Interlocked在多线程下进行原子操作,无锁无阻塞的实现线程运行状态判断
巧妙地使用Interlocked的各个方法,再无锁无阻塞的情况下判断出所有线程的运行完成状态. 昨晚耐着性子看完了clr via c#的第29章<<基元线程同步构造>>,尽管这 ...
- erl_0017 《硝烟中的erlang》 读书笔记004 “锁和阻塞”
如果某个进程需要持续地接收新任务,那么其在执行耗时过长的锁或者阻塞操作时,就会出现问题. 最为常见的例子之一就是:某个进程使用了TCP socket,阻塞在了接收新的连接或者等待消息上面.在执行此类阻 ...
- 一种在获取互斥锁陷入阻塞时可以被中断的 lock
经过上篇的实例 线程在陷入阻塞时,在sychronized获取互斥锁陷入阻塞时,我们是无法进行中断的,javase5中提供了一种解决的办法 ReentrantLock ,我们常常用到的是它的lock( ...
- sqlserver 锁与阻塞
DDL/索引重建 会申请 Sch-M锁 with (nolock) 会申请 Sch-S锁 with (nolock)会阻塞 sch-M, 同样Sch-M也会 阻塞with (nolock) 索引重建2 ...
- Sql Server 优化----SQL语句的执行方式与锁以及阻塞的关系
阻塞原因之一是不同的Session在访问同一张表的时候因为不兼容锁的原因造成的, 当前执行的SQL语句是否被阻塞(或者死锁),不仅跟当前表上的已有的锁有关,也会跟当前执行的SQL语句的执行方式有关 简 ...
- Oracle中的阻塞锁SQL(阻塞在哪个数据上)
SELECT ( '节点 ' || a.inst_id || ' session ' || a.sid || ...
- mysql5.6创建索引导致锁表阻塞查询
结论:添加索引时,若果有对该表的慢查询,会导致索引添加延时等待 添加索引语句:alter table tb_name add index idx_xx(col_name); 执行添加索引的SQ ...
随机推荐
- C#中调用python方法
最近因为项目设计,有部分使用Python脚本,因此代码中需要调用python方法. 1.首先,在c#中调用python必须安装IronPython,在 http://ironpython.codepl ...
- gulp实用插件总结
gulp-sass:预编译sass; gulp-imagemin:压缩png.jpj.git.svg格式图片 gulp-minfy-css:压缩css文件 gulp-rename 重命名文件,把一个文 ...
- 练习ajax的时候出现这个问题 还没解决
VM601:1 Uncaught SyntaxError: Unexpected end of JSON input 应该怎么办呢
- (转)将win7电脑无线网变身WiFi热点,让手机、笔记本共享上网
将win7电脑变身WiFi热点,让手机.笔记本共享上网 功能:开启windows 7的隐藏功能:虚拟WiFi和SoftAP(即虚拟无线AP),就可以让电脑变成无线路由器,实现共享上网,节省网费和路由器 ...
- oracle数据库导入导出
简单记录下数据泵导出导入expdp .impdp 和 普通导出导入 exp.imp 一.数据泵导出数据库(按用户)步骤: 1.以oracle用户登录oracle所在服务器,创建数据库备份文件目录 &g ...
- 普通用户使用dbms_xplan包需要有的权限
普通用户使用dbms_xplan包查看执行计划需要对v$sql.v$sql_plan.v$session及v$sql_plan_statistics_all这四个视图同时具有select权限. 如果普 ...
- 大数据存储:MongoDB实战指南——常见问题解答
锁粒度与并发性能怎么样? 数据库的读写并发性能与锁的粒度息息相关,不管是读操作还是写操作开始运行时,都会请求相应的锁资源,如果请求不到,操作就会被阻塞.读操作请求的是读锁,能够与其它读操作共享,但是当 ...
- Caused by: java.lang.UnsatisfiedLinkError...解决经历
Caused by: java.lang.UnsatisfiedLinkError: Couldn't load BaiduMapVOS_v2_1_3: findLibrary returned nu ...
- 【Bugly 技术干货】Android开发必备知识:为什么说Kotlin值得一试
1.Hello, Kotlin Bugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 1. ...
- chrome的自动缓存真是讨厌。
最近老是遇到这样一个问题,为什么我的代码改了,页面却一点变化都没有,难道代码错了,打开chrome的调试窗口一看,md,页面根本就没有刷新,逗你爹玩儿呢. 不过幸好,这该死的缓存是可以关闭的. F12 ...