最代码伊成的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头像

分享到:

最近浏览
kevindel LV159月29日
月亮月亮月亮星星星星星星
qinjinzhi123 LV19月20日
星星
1691806320 LV17月7日
星星
ysdy001 LV15月2日
星星
土豆有点烦 LV23月18日
星星星星
dujinwing LV23月12日
星星星星
林二少3月12日
暂无贡献等级
ldc199375 LV83月1日
月亮月亮
苗毅6666 LV271月20日
太阳月亮月亮星星星星星星
顶部客服微信二维码底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友