Cause: java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current
问题
具体的场景是,cat监控到查询报错。
报错信息
字面意思是,客户端取消数据库连接,于是报错。
这个报错分两个部分:
1.数据库服务器
ORA-01013: user requested cancel of current operation //这个是数据库服务器返回的错误
2.客户端
Cause: java.sql.SQLTimeoutException //这个是java里的异常调用栈
原因
原因1-数据库锁
网上搜了一下,说是锁的原因,所以开始以为是锁的原因,但是后面分析发现不是锁的原因,因为查询是普通的查询,普通的查询没有锁的问题,也就是说,任何锁,都不影响读。所以,报错应该不是因为这个原因。
原因2-客户端取消连接
根据报错信息字面的信息,就是因为客户端取消数据库连接。实际上,应该也是这个原因。但是,客户端为什么会取消数据库连接?根据报错信息的第一个部分,是超时。可是,为什么会超时?这个报错是间隔性的,一般情况都是正常的,在生产执行sql耗时不到1s,而且有的报错sql数据量比较小但是也会报错,所以也应该不是sql本身的问题。
到目前为止,没有找到本质的原因,只是知道字面的原因。所以,也没有办法解决。
其他信息
1.数据库连接池用了阿里的druid
这次上线更新了数据库连接池的配置,因为最近几天都在报错:连接重置,reset connection,recover connection,之类的报错信息。
原因是因为连接失效,解决方法是,开启连接池的空闲连接检查配置项。然后,这次上线就更新了数据库连接池的配置,连接重置的错误没了,但是上线之后,却又报错客户端取消连接。所以,也有可能是和这次更新了数据库连接池配置有关。但是其他的项目,配置也一样,却又没有报错。
2.执行了sql,也没有问题,耗时正常
虽然不是锁的原因,但是也找dba看了锁,也是正常的,即都是短暂的锁(多次执行查询锁的sql,锁记录一直在变),没有长期持有锁不释放的情况。
3.cat监控到每个报错信息,也有对应的慢sql(也有报错信息,即异常调用栈)
这个也和报错信息的第一部分也对的上,就是执行sql的时间超时了。但是不知道为什么超时。
4.数据库锁
其他部门也有同样的错误,而且是读写分离,所以更应该不是数据库锁的原因。
总结
1.不是同一笔订单报错,其他的订单号也有报错
2.应该不是锁的原因
1)没有长期没有释放的锁,我和dba一起确认,锁的占用都是短暂的,所以应该不是锁的原因
2)数据库的锁,不会影响查询,现在的查询只是普通的查询,所以应该不是锁的原因
3)问了其他部门,他们读写分离,查询的时候也有这个问题,所以应该不是锁的原因
3.应该是偶尔查询数据库时间太久导致
异常的时候,cat里的error和慢sql,都有异常,而且是同一笔订单。
具体分析是,由于数据库查询太久,应用超时,断开数据库连接,然后报错:ORA-01013: user requested cancel of current operation,即客户端取消了数据库连接。
本地模拟两个客户端的查询for update,后面的for update就会一直阻塞——停止后面的查询,也会报错提示:ORA-01013: user requested cancel of current operation。所以,客户端取消了连接,就会报错提示这个信息,在应用里比较可能的原因就是因为查询数据库太久导致应用超时,然后应用就取消了连接,从而报错这个提示信息。
解决方法
经过分析,不太可能是慢sql的问题,所以还是连接的问题。目前的连接失效检测,是大于最小数量的连接,才检测。所以还是存在连接失效的问题,如果连接失效,客户端和服务器都不知道,然后客户端超时,然后取消数据库连接,就可能会导致这个问题。
连接也可能被防火墙断开,防火墙一个小时会断开一次长连接。
所以,可以开启小于最小数量的连接失效检测,具体就是保活配置keepalive。
版本
保活功能是后面才加的,所以要用比较新的版本,目前用的1.1.9,虽然这个版本也支持,但是最好还是用新的版本,因为新版本修复了保活配置的bug。
推荐至少用1.1.16
1.1.21 //推荐
最新1.1.22
参考
https://github.com/alibaba/druid/wiki/KeepAlive_cn
知识点
数据库的锁
这里只讲数据库的行锁,一般两种情况会被锁住:
1.更新数据的时候,其他事务不能更新数据
2.查询 for update,其他事务不能更新数据
也就是说,以上两种情况,都不影响读数据,读数据是没有任何锁的,除非加了for update。
实际上,任何锁,都不影响读数据,至少不影响普通的查询,即查询没有加for uodate。
oracle-查询锁记录
Oracle数据库操作中,我们有时会用到锁表查询以及解锁和kill进程等操作,
那么这些操作是怎么实现的呢?本文我们主要就介绍一下这部分内容。
(1)锁表查询的代码有以下的形式:
(2)查看哪个表被锁
(3)查看是哪个session引起的
(4)杀掉对应进程
https://blog.csdn.net/wangchuanmei/article/details/80017108
共享锁和排他锁影响读吗?
共享锁和排它锁的区别不是说影响读,两个锁都不影响读,其实任何锁都不影响读。而是有其他的细节区别,具体区别不是重点,不讲。
因为测试的时候,不管是共享锁(查询 for update),还是排他锁(更新数据,即增删改),一个事务更新,另外一个事务仍然可以读数据。
测试
1.两个for update,后面的for update就会阻塞,因为获取锁但是获取不到
2.一个for uddate,一个普通查询,可以正常查询
3.一个更新,一个查询,可以正常查询
以上,都是在第一个操作不提交的情况下测试的。
补充
除了报错:客户端取消连接,现在仍然会报错-连接失效:
所以,应该还是失效连接的问题,具体原因就是小于最小数量的连接,没有检查失效连接,所以解决方法还是必须得配置保活keepAlive。
版权声明: 本文为 InfoQ 作者【青乡之b】的原创文章。
原文链接:【http://xie.infoq.cn/article/d515e4b40b68172a35cf31425】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论