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

本文深入分析了ORA-01013和SQLTimeoutException报错原因,探讨了数据库锁、客户端取消连接及超时等问题,提出了通过配置Druid连接池保活功能来解决连接失效的方法。

问题

具体的场景是,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.youkuaiyun.com/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。

<think>好的,我现在需要解决用户提出的关于Javajava.sql.SQLTimeoutException异常,特别是ORA-01013错误的问题。首先,我需要确认用户的具体需求和问题背景。 用户之前提到了ORA-00923错误,但这次的问题是ORA-01013,即“用户取消操作”。用户可能在使用Druid连接池连接Oracle数据库时遇到了超时问题,导致请求被取消。我需要结合之前的引用内容,特别是引用[2]中提到的SQLTimeoutException的原因和解决方法,来针对ORA-01013进行分析。 首先,ORA-01013错误通常表示用户或应用程序主动取消了正在执行的数据库操作。这可能由以下几个原因引起: 1. **查询超时设置过短**:如果应用程序设置了查询超时时间(如通过Statement.setQueryTimeout()),当查询执行时间超过这个阈值时,驱动会主动取消查询,触发此错误。 2. **连接池配置问题**:连接池(如Druid)可能配置了超时参数,比如连接等待超时或事务超时,导致长时间运行的查询被中断。 3. **资源争用或锁等待**:数据库中存在锁竞争或资源不足,导致查询长时间无法完成,最终被取消。 4. **网络问题**:不稳定的网络连接可能导致传输中断,触发操作取消。 5. **应用层逻辑**:应用程序可能在某个条件满足时主动取消查询,例如用户手动取消操作。 接下来,我需要逐一分析这些可能的原因,并提供相应的解决方案。需要确保建议的方法具体可行,并且结合用户提到的Druid配置和Oracle环境进行调整。 例如,针对查询超时设置过短,可以建议用户检查代码中的setQueryTimeout值,以及Druid的连接池配置,如maxWait等参数。对于SQL优化,可能需要分析慢查询,使用执行计划来优化索引或重构SQL语句。 此外,引用[2]中提到优化SQL和索引是解决超时的方法之一,因此需要强调这一点。同时,用户之前遇到的是配置Druid时的启动错误,但现在的问题是在运行时出现的超时,因此需要区分配置错误和运行时超时的不同处理方式。 最后,要确保回答结构清晰,分点说明原因和解决方案,并给出实际的配置示例或代码片段,帮助用户具体实施。同时,生成的相关问题需要与当前主题紧密相关,帮助用户进一步排查和优化。</think>### ORA-01013错误分析与解决方案 #### 错误背景 `java.sql.SQLTimeoutException: ORA-01013` 表示用户在数据库操作完成前主动取消了请求,通常与超时设置、资源竞争或SQL效率相关[^2]。 --- ### 一、根本原因分析 1. **查询超时设置过短** - 应用代码或连接池设置的超时阈值(如`Statement.setQueryTimeout()`)小于SQL实际执行时间。 - 示例:若设置`setQueryTimeout(5)`,但SQL需要10秒完成,则会被强制中断。 2. **连接池配置不当** - Druid连接池参数(如`maxWait`、`validationQueryTimeout`)设置过低。 - 引用案例:Druid默认`maxWait`为-1(无限等待),若手动调整为较小值可能导致超时[^1]。 3. **SQL效率低下** - 未优化的复杂查询、缺失索引或全表扫描导致执行时间过长。 - 示例:`SELECT * FROM large_table WHERE unindexed_column = ?`。 4. **数据库资源竞争** - 锁等待(如行锁、表锁)、高并发事务或数据库服务器负载过高。 5. **网络不稳定** - 数据传输延迟或中断触发操作取消。 --- ### 二、解决方案 #### 1. 调整超时配置 - **代码层**:检查并延长`Statement.setQueryTimeout()`值 ```java Statement stmt = connection.createStatement(); stmt.setQueryTimeout(30); // 单位:秒 ``` - **Druid连接池**:修改`maxWait`和超时参数 ```properties # application.properties spring.datasource.druid.maxWait=30000 # 单位:毫秒(30秒) spring.datasource.druid.validationQueryTimeout=30 ``` #### 2. SQL优化与索引改进 - **分析执行计划** 使用`EXPLAIN PLAN`定位慢查询: ```sql EXPLAIN PLAN FOR SELECT * FROM orders WHERE status = 'PENDING'; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); ``` - **添加索引** 为高频查询字段创建索引: ```sql CREATE INDEX idx_status ON orders(status); ``` #### 3. 数据库资源优化 - **监控锁竞争** 查询Oracle锁信息: ```sql SELECT * FROM v$locked_object; ``` - **调整事务隔离级别** 降低隔离级别(如从`SERIALIZABLE`改为`READ_COMMITTED`)。 #### 4. 网络与硬件排查 - 使用`tnsping`检测数据库连通性: ```bash tnsping ORACLE_SID ``` - 联系运维团队检查网络带宽和稳定性。 --- ### 三、验证步骤 1. 复现问题时抓取**SQL执行时间**和**数据库AWR报告**。 2. 通过Druid监控界面观察连接池使用情况: ```properties spring.datasource.druid.web-stat-filter.enabled=true spring.datasource.druid.stat-view-servlet.enabled=true ``` 3. 使用`ALTER SYSTEM KILL SESSION`终止长时间未完成的会话。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值