SQLTimeoutException-ORA01013-user-requested-cancel-of-current

41次阅读

共计 2888 个字符,预计需要花费 8 分钟才能阅读完成。

问题

具体的场景是,cat 监控到查询报错。

报错信息

Cause: java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current operation

字面意思是,客户端取消数据库连接,于是报错。

这个报错分两个部分:
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,之类的报错信息。
原因是因为连接失效,解决方法是,开启连接池的空闲连接检查配置项 testWhileIdle。然后,这次上线就更新了数据库连接池的配置,连接重置的错误没了,但是上线之后,却又报错客户端取消连接。所以,也有可能是和这次更新了数据库连接池配置有关。但是其他的项目,配置也一样,却又没有报错。

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/dr…

总结

数据库连接池 druid 如何保活?同时开启 1. testWhileIdle 配置 2.keepAlive 配置。

其他知识点

数据库的锁

这里只讲数据库的行锁,一般两种情况会被锁住:
1. 更新数据的时候,其他事务不能更新数据
2. 查询 for update,其他事务不能更新数据

也就是说,以上两种情况,都不影响读数据,读数据是没有任何锁的,除非加了 for update。

实际上,任何锁,都不影响读数据,至少不影响普通的查询,即查询没有加 for update。


oracle- 查询锁记录

Oracle 数据库操作中,我们有时会用到锁表查询以及解锁和 kill 进程等操作,
那么这些操作是怎么实现的呢?本文我们主要就介绍一下这部分内容。

(1)锁表查询的代码有以下的形式:

select count(*) from v$locked_object;  

select * from v$locked_object;

(2)查看哪个表被锁

select b.owner,b.object_name,a.session_id,a.locked_mode 
from v$locked_object a,dba_objects b 
where b.object_id = a.object_id;

(3)查看是哪个 session 引起的

select a.OS_USER_NAME, c.owner, c.object_name, b.sid, b.serial#, logon_time
from v$locked_object a, v$session b, dba_objects c
where a.session_id = b.sid
 and a.object_id = c.object_id
 order by b.logon_time;

(4)杀掉对应进程

执行命令:alter system kill session '1025,41';  需要用户有权限操作
其中 1025 为 sid,41 为 serial#.

https://blog.csdn.net/wangchu…


共享锁和排他锁影响读吗?

共享锁和排它锁的区别不是说影响读,两个锁都不影响读,其实任何锁都不影响读。而是有其他的细节区别,具体区别不是重点,不讲。

因为测试的时候,不管是共享锁(查询 for update),还是排他锁(更新数据,即增删改),一个事务更新,另外一个事务仍然可以读数据。


测试

1. 两个 for update,后面的 for update 就会阻塞,因为获取锁但是获取不到
2. 一个 for uddate,一个普通查询,可以正常查询
3. 一个更新,一个查询,可以正常查询

以上,都是在第一个操作不提交的情况下测试的。

正文完
 0