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

用户头像
青乡之b
关注
发布于: 2020 年 08 月 26 日

问题

具体的场景是,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,之类的报错信息。

原因是因为连接失效,解决方法是,开启连接池的空闲连接检查配置项。然后,这次上线就更新了数据库连接池的配置,连接重置的错误没了,但是上线之后,却又报错客户端取消连接。所以,也有可能是和这次更新了数据库连接池配置有关。但是其他的项目,配置也一样,却又没有报错。



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)锁表查询的代码有以下的形式:

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/wangchuanmei/article/details/80017108




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



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



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




测试



1.两个for update,后面的for update就会阻塞,因为获取锁但是获取不到

2.一个for uddate,一个普通查询,可以正常查询

3.一个更新,一个查询,可以正常查询



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



补充

除了报错:客户端取消连接,现在仍然会报错-连接失效:

2020-07-02 16:27:09.619|ERROR|pEMJhNXhtOyE-536-93|com.alibaba.druid.util.JdbcUtils.close:86||close statement error
java.sql.SQLRecoverableException: Closed Connection
at oracle.jdbc.driver.PhysicalConnection.needLine(PhysicalConnection.java:5416)
at oracle.jdbc.driver.OracleStatement.closeOrCache(OracleStatement.java:1585)
at oracle.jdbc.driver.OracleStatement.close(OracleStatement.java:1570)
at oracle.jdbc.driver.OracleStatementWrapper.close(OracleStatementWrapper.java:94)
at com.alibaba.druid.util.JdbcUtils.close(JdbcUtils.java:84)
at com.alibaba.druid.pool.vendor.OracleValidConnectionChecker.isValidConnection(OracleValidConnectionChecker.java:88)
at com.alibaba.druid.pool.DruidAbstractDataSource.testConnectionInternal(DruidAbstractDataSource.java:1361)
at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1297)
at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:4619)
at com.alibaba.druid.filter.FilterAdapter.dataSource_getConnection(FilterAdapter.java:2745)
at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:4615)
at com.alibaba.druid.filter.stat.StatFilter.dataSource_getConnection(StatFilter.java:680)
at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:4615)
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1231)



所以,应该还是失效连接的问题,具体原因就是小于最小数量的连接,没有检查失效连接,所以解决方法还是必须得配置保活keepAlive。



发布于: 2020 年 08 月 26 日 阅读数: 31
用户头像

青乡之b

关注

还未添加个人签名 2014.04.28 加入

还未添加个人简介

评论

发布
暂无评论
Cause: java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current