已注销用户的gravatar头像
已注销用户 2018-01-02 10:08:04
记录一次oracle锁表排除经历

    背景:功能代码都写好了,进入测试阶段后,测试妹子测功能的时候,一切数据填入都是对的也没有发生异常的情况下,突然开发的接口提示504了。

    排查经过:用idea排查之后发现在某一段代码里面,该更新的数据sql貌似没有被执行,于是开始查看sql如下:

update
		A  ad
		set ad.status='1',
		ad.update_date=sysdate,
		ad.amount=#{Amount}
		where ad.code = #{Code}
		and ad.verify = #{verifyCode}

咋一看 这条sql是没有任何毛病的,放在PL-SQL里面也是可以执行的,那么就不是这个sql语句的问题,为了重现这个bug,于是叫测试重新测试一下。重新debug,开始怀疑没有执行这sql语句的原因是因为事物的缘故,后来才发现是因为 这条 sql 执行了但是一直在执行没有返回的结果,所以最后接口给出的504。

最后,猜测可能被锁表了,执行如下sql:

SELECT object_name, machine, s.sid, s.serial# 
FROM gv$locked_object l, dba_objects o, gv$session s 
WHERE l.object_id = o.object_id 
AND l.session_id = s.sid; 

tips:执行这条sql 需要oracle DBA的权限,否则无法执行

查询出如图:

记录一次oracle锁表排除经历

这就说明真的被锁了,执行如下sql,先把锁住的表释放掉:

ALTER system kill session '630, 15423';

这里的后面两个数据就是 查询出来对应的SID 和 SERIAL# 

到这一步,你觉得问题就解决了吗?

事实问题并没有解决掉,从代码层面看了一圈,我确定没有问题,那么我就去找测试,我说怎么操作出来的,看了半天,好像操作没什么问题,后来才知道,测试在测过程的时候,需要查询数据库某一个字段,然后填入,然后做功能测试,也就是这一个查询导致了死锁。他的sql语句如下:


select * from A for update;

那么问题就来了,for update是什么鬼?相信很多牛牛们都可能不是很熟悉这个,大家用mysql 可能查询就是直接写

select * from 某某表 

关于for update 是什么玩意看如下内容:

如果只是select 的话,Oracle是不会加任何锁的,也就是Oracle select 读到的数据不会有任何限制,虽然这时候有可能另外一个进程正在修改表中的数据,并且修改的结果可能影响到你目前select语句的结果,但是因为没有锁,所以select结果为当前时刻表中记录的状态。

 如果加入了for update Oracle一旦发现(符合查询条件的)这批数据正在被修改,则不会发出该select语句查询,直到数据被修改结束(被commit),马上自动执行这个select语句。

如图:

记录一次oracle锁表排除经历

 说到这,原因出来了。如果在查询的时候加了for update并且没有commit的时候,再其他程序跑这个update 语句的时候表会被锁住,导致你程序的时候sql 没有执行响应,所以在查询的时候,建议不要轻易使用 for update 

后面还有 oracle for update 和 for update nowait的知识扩展,就不继续多费笔墨了。

附上链接 有需要的可以自行学习查看:https://www.cnblogs.com/quanweiru/archive/2012/11/09/2762223.html


打赏

已有1人打赏

最代码官方的gravatar头像
最近浏览
水光浮藻  LV6 2021年4月12日
ydyzzjsl 2021年3月10日
暂无贡献等级
jiangzhengtai  LV1 2020年9月22日
feiqinglee  LV1 2020年8月20日
zyk_zuidaima  LV1 2019年12月31日
lvbinbinsb  LV5 2019年10月22日
youwuzuichen  LV10 2019年10月4日
hadoopCJ  LV5 2019年9月25日
miaomiaosun 2019年6月29日
暂无贡献等级
cs383450139 2019年3月22日
暂无贡献等级
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友