nested exception is java.sql.SQLException: 关闭的连接

博客讲述了在应用上线后遇到的性能问题,表现为‘nested exception is java.sql.SQLException: 关闭的连接’异常。经过排查,问题在于SQL执行计划错误,全表扫描导致效率低下。解决方案包括定期分析表的统计信息或在SQL中添加执行计划提示。作者建议针对数据量变化大、性能要求高的表和SQL进行重点关注和优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间做一个后台系统,在开发测试环境应用运行的非常良好,没有出现任何的问题。

当测试完成上预发布时问题出现了,应用运行非常缓慢,一直停在某一个地方不执行,最后抛一个nested exception is java.sql.SQLException: 关闭的连接的异常,很时郁闷。刚开始碰到这个部题一直以为是我的连接池出现了问题,应用中事务太大,导致死锁等引起的。

网上也搜了一个遍,找到的答案基本都是说连接池配制有误,我用的C3P0的连接池,DB用的是oracle的,但一遍遍查应用,检查连接池配制,把超时设的很长各种方法都用尽了,最后还是不OK!

最后居然怀疑事务太大,所以就把设计做了变更,开发测试都没问题,但一上线,运行结果还是一样的问题,一度限入了僵局,难道是DB出现了问题?开发库测试库都是OK的。只能把问题定义到DB上去了

用select object_name,machine,s.sid,s.serial#
from v$locked_object l,dba_objects o ,v$session s
where l.object_id = o.object_id and l.session_id=s.sid;
查了一下数据库,发现有张表未做提交,可会话已结束,这就是应用已死提,对数据库操作未做提交!奇怪。。

没办法,只能开始慢慢查询,非常简单,我把应用启动起来,然后让DBA在DB上观看一下执行计划,问题找到了。

 

DBA回复:

delete from table_name where id = :1 ;

这条SQL走错了执行计划,用了全表扫描引起的。

今天在测试库发现SQL执行计划:

------------------------------------------------------------------------------------------

| Id  | Operation          | Name                | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------

|   0 | DELETE STATEMENT   |                     |     1 |    61 |  2161   (1)| 00:00:26 |

|   1 |  DELETE            | table_name  |       |       |            |          |

|*  2 |   TABLE ACCESS FULL| table_name |     1 |    61 |  2161   (1)| 00:00:26 |

------------------------------------------------------------------------------------------

分析表上的统计信息后走上了正确的执行计划:

--------------------------------------------------------------------------------------------

| Id  | Operation          | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------

|   0 | DELETE STATEMENT   |                        |     1 |    58 |     1   (0)| 00:00:01 |

|   1 |  DELETE            | table_name    |       |       |            |          |

|*  2 |   INDEX UNIQUE SCAN| table_name _UK |     1 |    58 |     1   (0)| 00:00:01 |

这个问题主要原因是表上频繁的插入删除,数据量的变化造成表上的统计信息陈旧,SQL未能用到正确的执行计划。

防止这个问题的方法有两种:

1.定时分析数据库中表的统计信息。(无需修改SQL,但需要数据库中增加JOB,并且确定分析的周期)

2。对SQL加hints固定执行计划。(修改SQL,但可保证无论何时均可以走到这个S_REAL_BIDWORD_COST_UK索引扫描)

第一种方法如果分析周期内数据量出现急剧变化仍会出现走错执行计划的风险,个人建议采用第二种,修改SQL如下:

delete /*+ index(a  table_name _UK )*/ from table_name   a where a.ID = :1 ;

 

SQL走错执行计划的问题解释一下:

1.这个跟是否创建了唯一索引是没有关系的。

2. 插入删除频度跟SQL走错执行计划是没有必然联系的。只能说插入删除较多的表,数据量变化很快,更容易出现这样的风险

就算插入删除操作很少的表,但某一天数据量急剧变化的情况(比如平日20W左右的数据量,某时批量插入了200w),也有可能会导致执行计划错误。

3.SQL走错执行计划跟SQL本身是没有关系,SQL的执行计划是由ORACLE内部算法生成(RBO,CBO),同一SQL可能拥有多个执行计划,ORACLE会根据表,索引等的信息来选择使用哪一个执行计划。比如某张表原来只有10条记录,ORACLE会认为走全表扫描会优于索引扫描,但当表记录变化到10w,可能走索引更快。

4。是否定时更新表上的统计信息就能解决这个问题呢?这一直是个争论的话题。官方也未有明确说法,所以这个风险在目前网站各个数据库都存在的,我们目前的解决方案是只对遇到问题表进行分析(已准备在11g的数据库上尝试由ORACLE定时任务去分析)

5.由于这个问题不确定性,性能测试其实是无法规避这个风险的。

6.我们这样做可以最大程度减小这个问题带来的风险:

   1。关注数据量巨大的表。(目前和预计增长很快的表)

   2。关注数据量变化较大的表(比如插入,删除频繁,有批量删除插入的表)

   3。关注SQL性能要求很高的SQL(执行频率很高的SQL)

总的说来这个问题不是程序BUG,不是SQL本身的问题,无法验证,其实也很难模拟重现。呵…毕竟ORACLE也是人写的程序没有那么十全十美,所以DBA每次新项目上线都会很关注是否有新的TOP SQL,偶尔会发现这样的问题,对需要关注的表和SQL大家做好沟通能最大程度减小这个风险。

 

 

 

 

 

### 解决 Java `SQLException` 中断异常的方法 当遇到类似于 `java.sql.SQLException: interrupt` 的错误时,通常意味着当前线程被中断而SQL操作未能完成。对于这种情况,有几种方法可以有效应对: #### 增加超时设置 如果问题是由于定时任务的超时时间短于实际业务逻辑所需的时间,则可以通过调整定时任务的最大允许运行时间为更合理的数值来解决问题[^3]。 ```xml <bean id="executorProperties" class="com.xxl.job.core.executor.impl.XxlJobSpringExecutor"> <!-- 设置更大的超时时间 --> <property name="timeout" value="600"/> </bean> ``` #### 使用异步执行模式 另一种方式是让业务代码采用异步机制,在不影响主线程的情况下继续处理长时间的任务。这样即使主流程结束也不会影响到后台仍在工作的子进程。 ```java // 异步调用服务层接口 @Service public class AsyncService { @Async public Future<Boolean> executeLongTimeTask() throws InterruptedException{ // 执行耗时较长的操作... Thread.sleep(5 * 60 * 1000); // 模拟五分钟后返回结果 return new AsyncResult<>(true); } } ``` #### 处理数据库连接池参数优化 适当增加数据库连接池中的最大活跃数(`maxActive`)以及最小闲置数量(`minIdle`)等属性可以帮助缓解因并发量过高而导致的部分请求无法及时获取资源的情况,从而减少因为等待过久引发的中断现象[^1]。 ```properties spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.minimum-idle=5 ``` 通过上述措施之一或组合应用,能够有效地降低甚至消除由 `java.sql.SQLException: interrupt` 引发的问题频率,提高系统的稳定性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值