[ 
https://issues.apache.org/jira/browse/DBCP-414?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13970043#comment-13970043
 ] 

Phil Steitz commented on DBCP-414:
----------------------------------

See comments on the duplicate issue, DBCP-415

> 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
>
> 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.2#6252)

Reply via email to