java.sql.SQLException: 关闭的连接

在业务高峰期,面对weblogic后台异常提示'java.sql.SQLException:关闭的连接',作者通过排查服务器补丁、数据库补丁、连接池配置及oracle会话限制等,最终发现是oracle的一个bug。通过修改相关SQL语句,成功解决了问题。
 

 最近工作中遇到一个非常奇怪的问题,数据库没有进行补丁修复,应用没有修改过,程序也没有变动过,但是weblogic后台一直报异常,信息如下:

java.sql.SQLException: 关闭的连接
        at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.ja
va:70)
        at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:1
12)
        at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java
:173)
        at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java
:229)
        at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java
:403)
        at oracle.jdbc.driver.PhysicalConnection.createStatement(PhysicalConnect
ion.java:2925)
        at oracle.jdbc.driver.PhysicalConnection.createStatement(PhysicalConnect
ion.java:2902)
        at weblogic.jdbc.wrapper.Connection.createStatement(Connection.java:443)

        at qqbean.sm.oms.system.service.OrderTimerBO.selectProductTeam(OrderTime
rBO.java:166)
        at qqbean.sm.oms.system.service.OrderReduceTimer.run(OrderReduceTimer.ja
va:38)
        at java.util.TimerThread.mainLoop(Timer.java:512)
        at java.util.TimerThread.run(Timer.java:462)

当前有事业务高峰期,功能部分好用,部分异常,电话一个接一个,头脑开始肿大。根据以上异常,自我判断为以下几点并根据以下

几点进行排查;

1、服务器进行补丁修复

      查看系统日志,未发现有补丁修复的记录,也没有weblogic应用异常的信息;排除该可能性;

2、数据库进行补丁修复

      联系IBM运维团队,并为对数据库进行补丁修复;排除该可能性;

3、weblogic连接池配置问题

       weblogic连接池进行测试连接没有问题,重启部署不能解决问题,郁闷中......

4、oracle的session超过系统最大值

       查看当前用户的session没有限制排除该问题;

 

百感交集在查看后台日志,看到如下信息:

[ERROR] AbstractDAO:314 - java.sql.SQLException: ORA-00600: internal error code,
 arguments: [kkslgbv0], [], [], [], [], [], [], []

 

根据这个错误得知是数据库的一个bug:

Bug 5155885  OERI[kkslgbv0] with CURSOR_SHARING=similar
 This note gives a brief overview of bug 5155885.
 The content was last updated on: 03-APR-2009

 
Click here for details of each of the sections below.
Affects:

Product (Component)Oracle Server (Rdbms)
Range of versions believed to be affectedVersions < 11
Versions confirmed as being affected
    • 10.2.0.3
Platforms affectedGeneric (all / most platforms affected)

Fixed:
This issue is fixed in
    • 10.2.0.2 Patch 6 on Windows Platforms
    • 10.2.0.3 Patch 1 on Windows Platforms
    • 10.2.0.3 Patch 24 on Windows Platforms
    • 10.2.0.4 (Server Patch Set)
    • 11.1.0.6 (Base Release)
Symptoms:Related To:
    • Internal Error May Occur (ORA-600)
    • ORA-600 [kkslgbv0]
    • Literal Replacement (CURSOR_SHARING)
    • CURSOR_SHARING
    • _OPTIM_PEEK_USER_BINDS

Description

    • A ORA-600 can occur while accessing a bind value while deciding whether
      to shared a cursor or not when literal replacement is enabled.


      Workaround
       Use CURSOR_SHARING=EXACT or set "_optim_peek_user_binds"=false so that

       bind values are not peeked.

Please note: The above is a summary description only. Actual symptoms can vary. Matching to any symptoms here does not confirm that you are encountering this problem. Always consult with Oracle Support for advice.

References

针对这个问题,修复bug可能会导致更严重的问题,于是准备从导致该bug的sql出手,避开该bug。功夫不负有心人,问题终于通过修改sql后得到解决。

<think> 我们正在处理一个关于Java数据库编程中出现的异常问题:java.sql.SQLException: 关闭的语句。根据引用[1]中的信息,这个异常通常与数据库连接或语句的关闭状态有关。然而,引用中提供的信息有限,我们需要结合常见的数据库编程实践来给出解决方案。 这个异常通常发生在尝试使用一个已经被关闭的PreparedStatement或Statement对象时。在Java JDBC编程中,Statement(包括PreparedStatement)在关闭后就不能再使用。如果程序试图调用已被关闭的Statement的方法(如executeQuery()),就会抛出这种异常。 解决思路: 1. 检查代码逻辑,确保在语句关闭后不再使用它。 2. 确保在使用语句对象之前,它没有被提前关闭。 3. 检查是否存在作用域问题,比如在一个方法内部创建的语句对象,在方法返回时被关闭,但后续又尝试在方法外部使用它。 4. 使用连接池时,检查连接关闭的行为,有时连接池可能会重用连接,但语句不会被重用。 具体步骤: 步骤1:定位异常发生的位置 查看异常堆栈跟踪,确定是代码的哪一行导致了异常。这将帮助你找到是在哪里使用了已关闭的语句。 步骤2:检查语句对象的关闭时机 在代码中,确保在语句使用完毕之前不要关闭它。通常,我们会使用try-with-resources结构(Java 7及以上)来自动关闭资源,但要注意,一旦语句在try块内关闭,就不能在块外使用。 例如,以下代码会导致异常,因为try-with-resources在try块结束时自动关闭了语句: ```java try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { // 执行查询 ResultSet rs = pstmt.executeQuery(); // 处理结果集 } // 在此之后,pstmt已经被关闭,不能再使用 ``` 如果你需要在try块外部使用结果集,那么不能使用try-with-resources自动关闭语句,而需要手动管理关闭。但是,要注意在结果集处理完毕后再关闭语句。 步骤3:避免在循环中重复关闭语句 如果你在循环中创建并关闭语句,然后在下一次循环迭代中再次使用同一个语句变量,那么在上一次循环中关闭的语句已经不可用。确保每次循环都创建新的语句对象。 步骤4:检查多线程环境 如果多个线程共享同一个语句对象,那么一个线程关闭了语句,另一个线程再使用它就会抛出此异常。语句对象不是线程安全的,每个线程应该使用自己的语句对象。 步骤5:检查连接关闭的影响 如果关闭连接,那么该连接上的所有语句也会被关闭。因此,如果在关闭连接后,又尝试使用该连接上的语句,也会导致异常。 步骤6:使用日志跟踪语句状态 你可以在关键点添加日志,记录语句的创建、使用和关闭,以便跟踪语句的生命周期。 示例代码(正确使用try-with-resources): ```java try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { // 设置参数 pstmt.setString(1, "value"); try (ResultSet rs = pstmt.executeQuery()) { while (rs.next()) { // 处理结果 } } // 结果集自动关闭 } // 连接和语句自动关闭 ``` 如果必须手动管理,确保在finally块中关闭资源,但要注意关闭的顺序(结果集->语句->连接)和空指针检查。 步骤7:重构代码,确保每个数据库操作独立 如果你的代码结构较复杂,考虑将每个数据库操作封装在独立的方法中,并在方法内部完成资源的创建和关闭。 总结:解决“java.sql.SQLException: 关闭的语句”的关键是确保在语句关闭后不再使用它,并且要管理好语句的生命周期,避免作用域和线程问题。 根据上述分析,你可以检查代码中是否存在上述问题。如果问题仍然存在,请提供相关的代码片段以便进一步分析。 相关问题: 1. 如何正确关闭JDBC资源? 2.Java中使用try-with-resources管理JDBC资源有什么好处? 3. 多线程环境下如何安全使用JDBC? </think>### 解决 java.sql.SQLException: 关闭的语句 异常的方法 该异常通常发生在试图使用已被关闭的 JDBC `Statement` 或 `PreparedStatement` 对象时。以下是详细的解决步骤: #### 1. **检查语句关闭时机** 确保在数据库操作完成前**不要提前关闭**语句对象: ```java // 错误示例:在结果集处理前关闭语句 try (PreparedStatement stmt = conn.prepareStatement(sql)) { ResultSet rs = stmt.executeQuery(); stmt.close(); // ✗ 提前关闭 while (rs.next()) { ... } // 触发异常 } // 正确示例 try (PreparedStatement stmt = conn.prepareStatement(sql); ResultSet rs = stmt.executeQuery()) { // ✓ 自动管理关闭顺序 while (rs.next()) { ... } } ``` #### 2. **管理资源生命周期** 使用 **try-with-resources**(Java 7+)自动管理关闭顺序: ```java try (Connection conn = dataSource.getConnection(); PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users"); ResultSet rs = stmt.executeQuery()) { while (rs.next()) { // 处理结果集 } } // 自动按 rs→stmt→conn 顺序关闭 ``` #### 3. **作用域问题排查** 确保语句对象**未被意外关闭**: ```java public ResultSet getData() throws SQLException { PreparedStatement stmt = conn.prepareStatement(sql); stmt.close(); // ✗ 方法返回前意外关闭 return stmt.executeQuery(); // 触发异常 } ``` #### 4. **连接池配置检查** 若使用连接池(如 HikariCP、DBCP),检查配置: ```yaml # HikariCP 配置示例 hikari: connection-timeout: 30000 maximum-pool-size: 20 idle-timeout: 600000 max-lifetime: 1800000 leak-detection-threshold: 5000 # ↗ 调高泄漏检测阈值 ``` #### 5. **框架整合注意点** 在 MyBatis 或 Spring JDBC 中: - 避免手动操作底层 Statement - 检查 Mapper 中是否错误关闭资源 - 确保 `@Transactional` 作用域内不重复关闭连接 #### 6. **多线程同步** 多线程环境下使用 ThreadLocal 隔离资源: ```java private ThreadLocal<PreparedStatement> stmtHolder = new ThreadLocal<>(); public void executeQuery() { PreparedStatement stmt = stmtHolder.get(); if (stmt == null || stmt.isClosed()) { // ✓ 检查状态 stmt = conn.prepareStatement(sql); stmtHolder.set(stmt); } // 使用stmt... } ``` #### 7. **日志诊断** 启用 JDBC 日志定位关闭位置: ```java // 添加日志参数到连接URL jdbc:mysql://localhost/db?logger=Slf4JLogger&profileSQL=true ``` > **关键原则**:语句对象的生命周期应严格遵守 **创建 → 使用 → 关闭** 顺序,且关闭操作必须在使用完**结果集之后**执行[^1]。 --- ### 相关问题 1. 如何正确使用 try-with-resources 管理 JDBC 资源? 2. 连接池配置不当会导致哪些常见的 JDBC 异常? 3. MyBatis 中如何避免语句对象被意外关闭? 4. 多线程环境下如何安全共享 JDBC 资源? 5. JDBC 驱动日志的启用和分析方法有哪些? [^1]: 引用自 Java JDBC 规范文档及常见连接池配置指南
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值