一次ORA-60的诊断

某服务器经常在执行批量更新时出现如下死锁错误,然后假死。作为一个正常的服务器,出错是允许的,假死是不允许的。


java.sql.BatchUpdateException: ORA-00060: deadlock detected while waiting for resource

at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10656)
at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)



这个问题很难重现。要解决此问题,先要能让它重现。野蛮的重现方法因多个服务器不能同时复盘故不可取,只有知道原因才好重现。

ora-60 错误是很有名的错误,google 到重现方法:

[quote]
两个session进入事务

session 1 update a
session 2 update b
session 1 update b (session 1 等待)
session 2 update a (session 1 出错)
[/quote]

此外,还有一种这样的路径:

[quote]
两个session进入事务

session 1 update a
session 2 update b
session 2 update a (session 2 等待)
session 1 update b (session 2 出错)
[/quote]

结论: 谁等待谁出错。

原理:等待者已申请的资源被先占者申请,先占者将抢到该资源,oracle 即通知等待者其申请作废。ora-60 错误就是这样一个通知。

可见,前面那个服务器有做等待。

然而,该 BatchUpdate 只操作一个表,不可能出现上面的等待。

通过翻阅 /product/app/oracle/admin/xxx/udump 中的 trace 信息,发现等待者和抢占者的语句均指向同一个表。两个session操作单表也可以死锁?

什么原因,忽然想到,行级锁!

原来,两个更新事务,彼此都在更新同一张表,假如都命中了 1、3 两行,一个按 1、3 次序命中,一个按 3、1 次序命中,就会出现上述错误了。

更小的试验是这样进行的:

[quote]
两个session进入事务

session 1 update a(1)
session 2 update a(3)
session 1 update a(3) (session 1 等待)
session 2 update a(1) (session 1 出错)
[/quote]

按此试验结果,在服务器中重现了该错误。

经重现后发现,假死原因是在使用连接池时,close(ps) 后再 prepareStatement().executeBatch 就会出现卡壳。

解决方法:在 BatchUpdateExcetion 后,应使用 ps.cancel() 释放 PrepareStatement 的事务。

再次试验问题得到解决。效果如何正在观察。


参考材料:

[url]http://oracle-error.blogspot.com/2008/10/ora-00060-deadlock-detected-while_20.html[/url]

[url]http://www.dnbcw.com/biancheng/oracle/ppse253790.html[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值