【问题标题】:Glassfish Connection Pool - java.sql.SQLException: Connection closedGlassfish 连接池 - java.sql.SQLException:连接已关闭
【发布时间】:2014-09-19 15:52:48
【问题描述】:

我正在使用 Oracle Glassfish Server Open Source Edition 4.0Oracle Database 11g(版本 11.2.0-1.0) 的 Web 项目 JSF2。 服务器和数据库在同一台 Windows 机器上运行。 连接池管理与数据库的连接。

有人知道为什么我有时会出现以下异常:

java.sql.SQLException: Connection closed
    at com.sun.gjc.spi.base.ConnectionHolder.checkValidity(ConnectionHolder.java:766)
    at com.sun.gjc.spi.base.ConnectionHolder.commit(ConnectionHolder.java:243)
    at de.mydomain.myproject.Hl7MessageHandler.run(Hl7MessageHandler.java:123)
    ...

或者有时这个:

java.sql.SQLRecoverableException: Closed connection
    at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:5675)
    at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:5735)
    at com.sun.gjc.spi.base.ConnectionHolder.commit(ConnectionHolder.java:244)
    at de.mydomain.myproject.Hl7MessageHandler.run(Hl7MessageHandler.java:123)
    ...

数据库类:

public static Connection getConnection() throws NamingException, SQLException {     
    Context initContext = new InitialContext(); 
    DataSource datasSource = (DataSource)initContext.lookup("jdbc/Oracle"); 
    Connection connnection = datasSource.getConnection();
    return connnection; 
}

servlet 中的请求处理:

public IResponseSendable<String> run(String hl7MsgString, boolean publishErrorToDB) {

    // ... do something

    try {
        con = Database.getConnection();
    } catch (NamingException | SQLException conExc) {

        return generateAck(true, conExc.getMessage(), hl7MsgString);        
    }

    try {
        con.setAutoCommit(false); 
        process();
        con.commit();
    } catch (HL7Exception | SQLException pe) {
        logger.error(...);

        // Exceptionhandling...

        try { 
            con.rollback();
        } catch (SQLException rollbackExc) { 
            logger.error(...);
        }           
        return generateAck(true, pe.getMessage(),hl7MsgString, _log);
    }
    finally {

        try { 
            con.setAutoCommit(true);
            con.close();
        } catch (SQLException e) { 
            logger.error(...);
        }
    }
    return generateAck(false, "", hl7MsgString);
}

过程-方法:

private void process() throws HL7Exception, SQLException {
    // Do something...

    String sql = "BEGIN save_patient_data(?,?,?,?,?,?,?); END;";

    CallableStatement stmt = (CallableStatement) con.prepareCall(sql);
    stmt.setString(1, ...);
    // ...

    stmt.registerOutParameter(6, java.sql.Types.VARCHAR);
    stmt.registerOutParameter(7, java.sql.Types.NUMERIC);
    stmt.execute(); 
    // ... 
    stmt.close();

    // More databse stored procedure can be called ...
}

连接池设置:

Initial and Minimum Pool Size: 10 Connections
Maximum Pool Size: 60 Connections
Pool Resize Quantity: 2 Connections
Idle Timeout: 600 Seconds
Max Wait Time: 0 Milliseconds

Validate At Most Once: 0 Seconds
Connection Leak Timeout: 10 Seconds
Connection Leak Reclaim: enabled
Statement Leak Timeout: 6 Seconds
Statement Leak Reclaim: enabled
Creation Retry Attempts: 0
Retry Interval: 10 Seconds

Connection Validation: Required
Validation Method: meta-data

数据库 IDLE-Timeout 设置为“UNLIMITED”。

通知: 调用“con.prepareCall(sql);”时发生异常(不能是第一次)或者当我尝试提交连接或稍后尝试打开自动提交时。

是否有人知道原因或调试应用程序以找出问题的最佳方法是什么?

谢谢。


编辑: 也许这很重要: 我可以在服务器日志中找到许多关于连接泄漏的警告:

2014-07-28T14:49:17.961+0200|Warnung: A potential connection leak detected for connection pool OraclePool. The stack trace of the thread is provided below : 
com.sun.enterprise.resource.pool.ConnectionPool.setResourceStateToBusy(ConnectionPool.java:324)
com.sun.enterprise.resource.pool.ConnectionPool.getResourceFromPool(ConnectionPool.java:758)
com.sun.enterprise.resource.pool.ConnectionPool.getUnenlistedResource(ConnectionPool.java:632)
com.sun.enterprise.resource.pool.AssocWithThreadResourcePool.getUnenlistedResource(AssocWithThreadResourcePool.java:200)
com.sun.enterprise.resource.pool.ConnectionPool.internalGetResource(ConnectionPool.java:526)
com.sun.enterprise.resource.pool.ConnectionPool.getResource(ConnectionPool.java:381)
com.sun.enterprise.resource.pool.PoolManagerImpl.getResourceFromPool(PoolManagerImpl.java:245)
com.sun.enterprise.resource.pool.PoolManagerImpl.getResource(PoolManagerImpl.java:170)
com.sun.enterprise.connectors.ConnectionManagerImpl.getResource(ConnectionManagerImpl.java:360)
com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:307)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:196)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:171)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:166)
com.sun.gjc.spi.base.AbstractDataSource.getConnection(AbstractDataSource.java:114)
de.mydomain.myproject.utilities.Database.getConnection(Database.java:17)
...

【问题讨论】:

    标签: jsf-2 jdbc oracle11g connection-pooling glassfish-4


    【解决方案1】:

    您启用了连接泄漏回收,连接泄漏超时为 10 秒。这意味着如果你持有一个逻辑连接超过 10 秒,它会被连接池管理器强行撤销和关闭(并且物理连接返回到连接池)。后续尝试使用逻辑连接将导致SQLException,因为连接已关闭。

    找出哪个操作花费的时间超过 10 秒,并尝试减少花费的时间配置更长的连接泄漏超时(恕我直言,10 秒对于连接泄漏检测来说有点短)。同样的 BTW 适用于您的语句泄漏检测(6 秒也很短)。

    【讨论】:

    • 一个好主意。我将关闭连接泄漏检测并重试。
    • 我试图调试抛出 SQLException: 142, 8129, 533, 71, 83, 915 需要多长时间(毫秒)......所以我不认为这 10 秒是简而言之:(还有其他想法吗?
    • @user3608395 您是否从获得连接到异常发生的时间(8192 毫秒也非常接近 10 秒)?在任何情况下,您包含的日志记录还表明检测到连接泄漏(请注意,此检测仅基于连接打开的时间长短,它不适用进一步的“智能”)。
    • 连接和语句泄漏超时和回收已关闭。但问题仍然不受影响!
    • @user3608395 您的日志是否仍然包含连接泄漏警告?还要确保不要将连接存储在方法的本地,而不是存储在实例变量中。
    猜你喜欢
    • 2015-11-03
    • 2016-07-01
    • 2011-08-02
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多