[
https://issues.apache.org/jira/browse/DBCP-414?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16021145#comment-16021145
]
Torsten Mielke commented on DBCP-414:
-------------------------------------
Apologies for commenting on this old bug but is someone able to clarify if this
bug would likely also exist on version 1.4?
I understand it was raised against version 2.0 and wonder if this could also
show up on 1.4...
Any feedback is highly appreciated.
> PoolablePreparedStatement can get closed while it's being used
> --------------------------------------------------------------
>
> Key: DBCP-414
> URL: https://issues.apache.org/jira/browse/DBCP-414
> Project: Commons Dbcp
> Issue Type: Bug
> Affects Versions: 2.0
> Environment: DBCP 2.0
> Reporter: Pasi Eronen
> Fix For: 2.0.1
>
>
> I've found a case where a PoolablePreparedStatement that's currently in
> active use can get closed (resulting in "PoolablePreparedStatement with
> address: ... is closed" SQLException to the application), from a finalizer of
> another DelegatingPreparedStatement (that's obviously not in use, since it's
> being garbage collected).
> Details:
> 0. Starting point: application has a Connection (it's a
> PoolGuardConnectionWrapper wrapping PoolableConnection wrapping
> PoolingConnection wrapping com.mysql.jdbc.JDBC4Connection), statement pooling
> is enabled, and prepareStatement has never been called
> 1. Application calls conn.prepareStatement. The statement pool is empty, so
> this ends up in PoolingConnection.makeObject, which then calls MySQL to get a
> PreparedStatement (stmt1), and wraps it in PoolablePreparedStatement (stmt2).
> PoolableConnection.prepareStatement wraps it in new
> DelegatingPreparedStatement (stmt3), and PoolGuardConnectionWrapper wraps it
> again (stmt4).
> 2. Application does something with stmt4, and eventually calls stmt4.close().
> The call ends up in stmt2.close (in PoolablePreparedStatement) which returns
> stmt2 to the statement pool. Stmt2.passivate() gets called, setting the
> _closed flag to true.
> 3. Application forgets all about stmt4
> 4. Later, application calls conn.prepareStatement (with same SQL) again. The
> result is the old MySQL PreparedStatement (stmt1) wrapped in the old
> PoolablePreparedStatement (stmt2) wrapped in new DelegatingPreparedStatement
> stmt5 wrapped in new DelegatingPreparedStatement stmt6. Stmt2.activate()
> gets called, setting the _closed flag to false.
> 5. Now, garbage collection gets run, and stmt4 gets gc'd. stmt4.finalize()
> calls stmt4.close() which calls stmt3.close() which calls stmt2.close().
> Since stmt2 is not closed any more (_closed was just set to false above), it
> gets closed and returned to the pool.
> 6. Applications calls something in stmt6, which ends up in stmt2, and
> stmt2.checkOpen() throws exception java.sql.SQLException:
> org.apache.commons.dbcp2.PoolablePreparedStatement with address:
> "com.mysql.jdbc.ServerPreparedStatement[12] - select 1" is closed.
> PoolGuardConnectionWrapper prevents the application from accidentally calling
> stmt4.close() later again, but this doesn't prevent the finalizer.... DBCP
> 1.4 did not have any finalizers, so it doesn't have this bug.
> I guess DelegatingStatement.close() should check isClosed(), and in the
> finally block, also do setDelegate(null) (like PoolGuardConnectionWrapper
> does), to make sure the delegate (which might be in active use by someone
> else) can never get called via this DelegatingStatement again (although most
> methods in DelegatingStatement start with checkOpen(), not all of them do!).
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)