mybatis/mybatis-3 · error · SQLException
Error accessing PooledConnection. Connection is invalid.
Error message
Error accessing PooledConnection. Connection is invalid.
What it means
PooledConnection is a dynamic proxy around a real JDBC Connection managed by PooledDataSource. When the pool invalidates a connection (it was closed back to the pool, detected as broken, or the pool was force-closed), the 'valid' flag is set false. Any subsequent method call on the proxy goes through checkConnection() and throws SQLException 'Error accessing PooledConnection. Connection is invalid.' instead of silently hitting a dead real connection.
Source
Thrown at src/main/java/org/apache/ibatis/datasource/pooled/PooledConnection.java:267
dataSource.pushConnection(this);
return null;
}
try {
if (!Object.class.equals(method.getDeclaringClass())) {
// issue #579 toString() should never fail
// throw an SQLException instead of a Runtime
checkConnection();
}
return method.invoke(realConnection, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
private void checkConnection() throws SQLException {
if (!valid) {
throw new SQLException("Error accessing PooledConnection. Connection is invalid.");
}
}
}
View on GitHub (pinned to 008069adb1)
Solutions
- Never cache or reuse a Connection after close() — get a fresh one from dataSource.getConnection() for each unit of work
- Audit code paths where the connection reference escapes (passed to helpers, stored in fields/ThreadLocal) and scope them to a try-with-resources block
- If forceCloseAll is being triggered (e.g., by finalize or a lifecycle hook), fix the shutdown ordering so workers finish before the pool closes
- Catch SQLException on connection use and re-acquire a connection if the message indicates invalidity (defensive, only for connection-survival logic)
Example fix
// before
Connection c = pooledDataSource.getConnection();
// ... later, after c.close() returned it to the pool
c.createStatement().execute(q); // SQLException: invalid
// after
try (Connection c = pooledDataSource.getConnection();
Statement st = c.createStatement()) {
st.execute(q);
} Defensive patterns
Strategy: validation
Validate before calling
// MyBatis PooledConnection exposes no public isValid of its own;
// validate by checking your own usage discipline instead:
// never use a Connection reference after close().
// With the pool, you may probe cheaply:
try (Connection c = pooledDataSource.getConnection()) {
if (c.isValid(1)) { /* proceed */ }
} Try / catch
try {
stmt = conn.createStatement();
} catch (SQLException e) {
if ("Error accessing PooledConnection. Connection is invalid.".equals(e.getMessage())) {
conn = pooledDataSource.getConnection(); // re-acquire and retry once
} else throw e;
} Prevention
- Scope every Connection to try-with-resources; no fields, no ThreadLocals, no escaping references
- Do not share one connection across components where one may close it
- Close workers before closing the pool at shutdown
When it happens
Trigger: Holding a Connection obtained from PooledDataSource after returning it to the pool (e.g., via close()) and then calling createStatement()/prepareStatement() on the stale reference; using a connection after PooledDataSource.forceCloseAll(); keeping connections past their pool lifetime; two parts of the code sharing one proxied Connection where one closes it.
Common situations: Custom connection management code that caches java.sql.Connection references instead of asking the pool each time; wrappers that call close() then continue using the connection; shutdown hooks or tests that force-close the pool while workers still use connections; Spring-managed code mixing pooled and raw connections.
Related errors
- A Cursor is already closed.
- PooledDataSource: Could not get a good connection to the dat
- PooledDataSource: Unknown severe error condition. The conne
- Executor was closed.
- Cannot commit, transaction is already closed
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/5c6bbf5f239ae552.
Report an issue: GitHub.