📄 connectionmanager.java
字号:
// $Id: ConnectionManager.java 9593 2006-03-10 17:08:38Z steve.ebersole@jboss.com $
package org.hibernate.jdbc;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.util.JDBCExceptionReporter;
/**
* Encapsulates JDBC Connection management logic needed by Hibernate.
* <p/>
* The lifecycle is intended to span a logical series of interactions with the
* database. Internally, this means the the lifecycle of the Session.
*
* @author Steve Ebersole
*/
public class ConnectionManager implements Serializable {
private static final Log log = LogFactory.getLog( ConnectionManager.class );
public static interface Callback {
public void connectionOpened();
public void connectionCleanedUp();
public boolean isTransactionInProgress();
}
private transient SessionFactoryImplementor factory;
private final Callback callback;
private final ConnectionReleaseMode releaseMode;
private transient Connection connection;
private transient Connection borrowedConnection;
private final boolean wasConnectionSupplied;
private transient Batcher batcher;
private transient Interceptor interceptor;
private boolean isClosed;
private transient boolean isFlushing;
/**
* Constructs a ConnectionManager.
* <p/>
* This is the form used internally.
*
* @param factory The SessionFactory.
* @param callback An observer for internal state change.
* @param releaseMode The mode by which to release JDBC connections.
* @param connection An externally supplied connection.
*/
public ConnectionManager(
SessionFactoryImplementor factory,
Callback callback,
ConnectionReleaseMode releaseMode,
Connection connection,
Interceptor interceptor) {
this.factory = factory;
this.callback = callback;
this.interceptor = interceptor;
this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );
this.connection = connection;
wasConnectionSupplied = ( connection != null );
this.releaseMode = wasConnectionSupplied ? ConnectionReleaseMode.ON_CLOSE : releaseMode;
}
/**
* Private constructor used exclusively from custom serialization
*/
private ConnectionManager(
SessionFactoryImplementor factory,
Callback callback,
ConnectionReleaseMode releaseMode,
Interceptor interceptor,
boolean wasConnectionSupplied,
boolean isClosed) {
this.factory = factory;
this.callback = callback;
this.interceptor = interceptor;
this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );
this.wasConnectionSupplied = wasConnectionSupplied;
this.isClosed = isClosed;
this.releaseMode = wasConnectionSupplied ? ConnectionReleaseMode.ON_CLOSE : releaseMode;
}
/**
* The session factory.
*
* @return the session factory.
*/
public SessionFactoryImplementor getFactory() {
return factory;
}
/**
* The batcher managed by this ConnectionManager.
*
* @return The batcher.
*/
public Batcher getBatcher() {
return batcher;
}
/**
* Was the connection being used here supplied by the user?
*
* @return True if the user supplied the JDBC connection; false otherwise
*/
public boolean isSuppliedConnection() {
return wasConnectionSupplied;
}
/**
* Retrieves the connection currently managed by this ConnectionManager.
* <p/>
* Note, that we may need to obtain a connection to return here if a
* connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
* or has previously been aggressively released (if supported in this environment).
*
* @return The current Connection.
*
* @throws HibernateException Indicates a connection is currently not
* available (we are currently manually disconnected).
*/
public Connection getConnection() throws HibernateException {
if ( isClosed ) {
throw new HibernateException( "connection manager has been closed" );
}
if ( connection == null ) {
openConnection();
}
return connection;
}
public boolean hasBorrowedConnection() {
// used from testsuite
return borrowedConnection != null;
}
public Connection borrowConnection() {
if ( isClosed ) {
throw new HibernateException( "connection manager has been closed" );
}
if ( isSuppliedConnection() ) {
return connection;
}
else {
if ( borrowedConnection == null ) {
borrowedConnection = BorrowedConnectionProxy.generateProxy( this );
}
return borrowedConnection;
}
}
public void releaseBorrowedConnection() {
if ( borrowedConnection != null ) {
borrowedConnection = null;
BorrowedConnectionProxy.renderUnuseable( borrowedConnection );
}
}
/**
* Is the connection considered "auto-commit"?
*
* @return True if we either do not have a connection, or the connection
* really is in auto-commit mode.
*
* @throws SQLException Can be thrown by the Connection.isAutoCommit() check.
*/
public boolean isAutoCommit() throws SQLException {
return connection == null || connection.getAutoCommit();
}
/**
* Will connections be release after each statement execution?
* <p/>
* Connections will be released after each statement if either:<ul>
* <li>the defined release-mode is {@link ConnectionReleaseMode#AFTER_STATEMENT}; or
* <li>the defined release-mode is {@link ConnectionReleaseMode#AFTER_TRANSACTION} but
* we are in auto-commit mode.
* <p/>
* release-mode = {@link ConnectionReleaseMode#ON_CLOSE} should [b]never[/b] release
* a connection.
*
* @return True if the connections will be released after each statement; false otherwise.
*/
public boolean isAggressiveRelease() {
if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
return true;
}
else if ( releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
boolean inAutoCommitState;
try {
inAutoCommitState = isAutoCommit()&& !callback.isTransactionInProgress();
}
catch( SQLException e ) {
// assume we are in an auto-commit state
inAutoCommitState = true;
}
return inAutoCommitState;
}
return false;
}
/**
* Modified version of {@link #isAggressiveRelease} which does not force a
* transaction check. This is solely used from our {@link #afterTransaction}
* callback, so no need to do the check; plus it seems to cause problems on
* websphere (god i love websphere ;)
* </p>
* It uses this information to decide if an aggressive release was skipped
* do to open resources, and if so forces a release.
*
* @return True if the connections will be released after each statement; false otherwise.
*/
private boolean isAggressiveReleaseNoTransactionCheck() {
if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
return true;
}
else {
boolean inAutoCommitState;
try {
inAutoCommitState = isAutoCommit();
}
catch( SQLException e ) {
// assume we are in an auto-commit state
inAutoCommitState = true;
}
return releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION && inAutoCommitState;
}
}
/**
* Is this ConnectionManager instance "logically" connected. Meaning
* do we either have a cached connection available or do we have the
* ability to obtain a connection on demand.
*
* @return True if logically connected; false otherwise.
*/
public boolean isCurrentlyConnected() {
return wasConnectionSupplied ? connection != null : !isClosed;
}
/**
* To be called after execution of each JDBC statement. Used to
* conditionally release the JDBC connection aggressively if
* the configured release mode indicates.
*/
public void afterStatement() {
if ( isAggressiveRelease() ) {
if ( isFlushing ) {
log.debug( "skipping aggressive-release due to flush cycle" );
}
else if ( batcher.hasOpenResources() ) {
log.debug( "skipping aggresive-release due to open resources on batcher" );
}
else if ( borrowedConnection != null ) {
log.debug( "skipping aggresive-release due to borrowed connection" );
}
else {
aggressiveRelease();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -