{"record":{"id":"035c83427465f44a","repo":"alibaba/druid","slug":"datasource-already-closed-at","errorCode":null,"errorMessage":"dataSource already closed at {}","messagePattern":"dataSource already closed at (.+?)","errorType":"exception","errorClass":"DataSourceClosedException","httpStatus":null,"severity":"critical","filePath":"core/src/main/java/com/alibaba/druid/pool/DruidDataSource.java","lineNumber":1553,"sourceCode":"            discardCount++;\n\n            holder.discard = true;\n\n            int fillCount = minIdle - (activeCount + poolingCount + createTaskCount);\n            if (fillCount > 0) {\n                emptySignalCalled = true;\n                emptySignal(fillCount);\n            }\n        } finally {\n            lock.unlock();\n        }\n        return emptySignalCalled;\n    }\n\n    private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException {\n        if (closed) {\n            connectErrorCountUpdater.incrementAndGet(this);\n            throw new DataSourceClosedException(\"dataSource already closed at \" + new Date(closeTimeMillis));\n        }\n\n        if (!enable) {\n            connectErrorCountUpdater.incrementAndGet(this);\n\n            if (disableException != null) {\n                throw disableException;\n            }\n\n            throw new DataSourceDisableException();\n        }\n\n        final int maxWaitThreadCount = this.maxWaitThreadCount;\n\n        DruidConnectionHolder holder;\n\n        long startTime = System.currentTimeMillis();  //进入循环等待之前，先记录开始尝试获取连接的时间\n        final long expiredTime = startTime + maxWait;","sourceCodeStart":1535,"sourceCodeEnd":1571,"githubUrl":"https://github.com/alibaba/druid/blob/fa8dc9912637a2f729eef9f55356621fec18d40e/core/src/main/java/com/alibaba/druid/pool/DruidDataSource.java#L1535-L1571","documentation":"DataSourceClosedException (a SQLException subclass) thrown by getConnectionInternal when the datasource has been closed (closed == true). The message includes the close timestamp (closeTimeMillis) so callers can see when the pool was shut down. Once closed, the pool will not hand out connections and every getConnection fails fast.","triggerScenarios":"getConnection/getConnectionInternal is called after dataSource.close() ran (or after restart()/a fatal error closed it). The closed check at line 1551 throws, incrementing connectErrorCount.","commonSituations":"Application shutdown closing the datasource while request threads still call getConnection(); a health-check/fatal-error path that closed the pool; calling close() explicitly then reusing the bean; JUnit teardown ordering closing the pool before an async assertion runs.","solutions":["Do not call getConnection() after close(); coordinate shutdown so callers stop before the pool closes.","If the pool closed due to an error, inspect logs for the originating fatal condition and restart/recreate the datasource.","Guard call sites: check dataSource.isClosed() (or isInited()) before borrowing, or wrap borrowing in a resilient client that recreates the pool.","Ensure test/teardown ordering does not close the shared datasource while background threads are still using it."],"exampleFix":"// before\npublic Connection borrow() throws SQLException {\n    return dataSource.getConnection(); // throws DataSourceClosedException after shutdown\n}\n// after\npublic Connection borrow() throws SQLException {\n    if (dataSource.isClosed()) {\n        throw new IllegalStateException(\"pool closed; recreate before use\");\n    }\n    return dataSource.getConnection();\n}","handlingStrategy":"validation","validationCode":"if (dataSource.isClosed()) {\n    throw new IllegalStateException(\"datasource closed at \" + new Date(dataSource.getCloseTimeMillis())\n        + \"; recreate before borrowing\");\n}\nConnection c = dataSource.getConnection();","typeGuard":null,"tryCatchPattern":"try {\n    return dataSource.getConnection();\n} catch (com.alibaba.druid.pool.DataSourceClosedException e) {\n    LOG.error(\"pool closed at {}; recreate datasource\", new Date(dataSource.getCloseTimeMillis()));\n    throw new IllegalStateException(\"datasource closed; recreate required\", e);\n}","preventionTips":["Coordinate shutdown so callers stop borrowing before close().","Guard call sites with isClosed() where reordering is possible.","Investigate fatal errors that auto-close the pool and recreate it."],"tags":["lifecycle","closed","shutdown","connection"],"backgroundTag":null,"analyzedSha":"fa8dc9912637a2f729eef9f55356621fec18d40e","analyzedAt":"2026-08-14T04:55:06.789Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}