HHH-14143 Detect illegal concurrent usage of LogicalConnectionManagedImpl

This commit is contained in:
Sanne Grinovero 2020-08-10 11:22:47 +02:00
parent 96bc705d9a
commit 2587709603
1 changed files with 19 additions and 5 deletions

View File

@ -14,6 +14,7 @@ import java.sql.SQLException;
import org.hibernate.ConnectionAcquisitionMode; import org.hibernate.ConnectionAcquisitionMode;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.ResourceClosedException; import org.hibernate.ResourceClosedException;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
@ -28,6 +29,9 @@ import org.jboss.logging.Logger;
/** /**
* Represents a LogicalConnection where we manage obtaining and releasing the Connection as needed. * Represents a LogicalConnection where we manage obtaining and releasing the Connection as needed.
* This implementation does not claim to be threadsafe and is not designed to be used by multiple
* threads, yet we do apply a limited amount of care to be able to void obscure exceptions when
* this class is used in the wrong way.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -190,23 +194,33 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
} }
private void releaseConnection() { private void releaseConnection() {
if ( physicalConnection == null ) { //Some managed containers might trigger this release concurrently:
//this is not how they should do things, still we make a local
//copy of the variable to prevent confusing errors due to a race conditions
//(to trigger a more clear error, if any).
final Connection localVariableConnection = this.physicalConnection;
if ( localVariableConnection == null ) {
return; return;
} }
try { try {
if ( !physicalConnection.isClosed() ) { if ( ! localVariableConnection.isClosed() ) {
sqlExceptionHelper.logAndClearWarnings( physicalConnection ); sqlExceptionHelper.logAndClearWarnings( localVariableConnection );
} }
jdbcConnectionAccess.releaseConnection( physicalConnection ); jdbcConnectionAccess.releaseConnection( localVariableConnection );
} }
catch (SQLException e) { catch (SQLException e) {
throw sqlExceptionHelper.convert( e, "Unable to release JDBC Connection" ); throw sqlExceptionHelper.convert( e, "Unable to release JDBC Connection" );
} }
finally { finally {
observer.jdbcConnectionReleaseEnd(); observer.jdbcConnectionReleaseEnd();
physicalConnection = null; boolean concurrentUsageDetected = ( this.physicalConnection == null );
this.physicalConnection = null;
getResourceRegistry().releaseResources(); getResourceRegistry().releaseResources();
if ( concurrentUsageDetected ) {
throw new HibernateException( "Detected concurrent management of connection resources." +
" This might indicate a multi-threaded use of Hibernate in combination with managed resources, which is not supported." );
}
} }
} }