背景:功能代码都写好了,进入测试阶段后,测试妹子测功能的时候,一切数据填入都是对的也没有发生异常的情况下,突然开发的接口提示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的权限,否则无法执行
查询出如图:
这就说明真的被锁了,执行如下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语句。
如图:
说到这,原因出来了。如果在查询的时候加了for update并且没有commit的时候,再其他程序跑这个update 语句的时候表会被锁住,导致你程序的时候sql 没有执行响应,所以在查询的时候,建议不要轻易使用 for update
后面还有 oracle for update 和 for update nowait的知识扩展,就不继续多费笔墨了。
附上链接 有需要的可以自行学习查看:https://www.cnblogs.com/quanweiru/archive/2012/11/09/2762223.html