HHH-5782 HHH-5783 : Remove "throws SQLException" from ConnectionManager methods; ConnectionManager should set timeout

This commit is contained in:
Gail Badner 2010-12-09 20:23:08 -08:00
parent b006a6c3c5
commit e7daff9d93
6 changed files with 164 additions and 163 deletions

View File

@ -41,11 +41,11 @@ import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Interceptor; import org.hibernate.Interceptor;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.TransactionException;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder; import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
import org.hibernate.engine.jdbc.spi.ConnectionManager; import org.hibernate.engine.jdbc.spi.ConnectionManager;
import org.hibernate.engine.jdbc.spi.ConnectionObserver; import org.hibernate.engine.jdbc.spi.ConnectionObserver;
import org.hibernate.engine.jdbc.spi.LogicalConnection;
import org.hibernate.jdbc.Batcher; import org.hibernate.jdbc.Batcher;
import org.hibernate.jdbc.Expectation; import org.hibernate.jdbc.Expectation;
@ -72,6 +72,8 @@ public class ConnectionManagerImpl implements ConnectionManager {
private transient Interceptor interceptor; private transient Interceptor interceptor;
private final Callback callback; private final Callback callback;
private long transactionTimeout = -1;
boolean isTransactionTimeoutSet;
private transient LogicalConnectionImpl logicalConnection; private transient LogicalConnectionImpl logicalConnection;
@ -269,6 +271,7 @@ public class ConnectionManagerImpl implements ConnectionManager {
log.debug( "transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!" ); log.debug( "transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!" );
} }
} }
unsetTransactionTimeout();
} }
private boolean isAfterTransactionRelease() { private boolean isAfterTransactionRelease() {
@ -285,9 +288,31 @@ public class ConnectionManagerImpl implements ConnectionManager {
@Override @Override
public void setTransactionTimeout(int seconds) { public void setTransactionTimeout(int seconds) {
logicalConnection.setTransactionTimeout( seconds ); isTransactionTimeoutSet = true;
transactionTimeout = System.currentTimeMillis() / 1000 + seconds;
} }
/**
* Unset the transaction timeout, called after the end of a
* transaction.
*/
private void unsetTransactionTimeout() {
isTransactionTimeoutSet = false;
}
private void setStatementTimeout(PreparedStatement preparedStatement) throws SQLException {
if ( isTransactionTimeoutSet ) {
int timeout = (int) ( transactionTimeout - ( System.currentTimeMillis() / 1000 ) );
if ( timeout <= 0) {
throw new TransactionException("transaction timeout expired");
}
else {
preparedStatement.setQueryTimeout(timeout);
}
}
}
/** /**
* To be called after Session completion. Used to release the JDBC * To be called after Session completion. Used to release the JDBC
* connection. * connection.
@ -387,31 +412,49 @@ public class ConnectionManagerImpl implements ConnectionManager {
afterStatement(); afterStatement();
} }
private abstract class StatementPreparer {
private final String sql;
StatementPreparer(String sql) {
this.sql = getSQL( sql );
}
public String getSqlToPrepare() {
return sql;
}
abstract PreparedStatement doPrepare() throws SQLException;
public void afterPrepare(PreparedStatement preparedStatement) throws SQLException {
setStatementTimeout( preparedStatement );
}
}
/** /**
* Get a non-batchable prepared statement to use for inserting / deleting / updating, * Get a non-batchable prepared statement to use for inserting / deleting / updating,
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}). * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}).
*/ */
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) public PreparedStatement prepareStatement(String sql, final int autoGeneratedKeys)
throws SQLException, HibernateException { throws HibernateException {
if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) { if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) {
checkAutoGeneratedKeysSupportEnabled(); checkAutoGeneratedKeysSupportEnabled();
} }
executeBatch(); StatementPreparer statementPreparer = new StatementPreparer( sql ) {
return proxiedConnection.prepareStatement( public PreparedStatement doPrepare() throws SQLException {
getSQL( sql ), return proxiedConnection.prepareStatement( getSqlToPrepare(), autoGeneratedKeys );
autoGeneratedKeys }
); };
return prepareStatement( statementPreparer, true );
} }
/** /**
* Get a non-batchable prepared statement to use for inserting / deleting / updating. * Get a non-batchable prepared statement to use for inserting / deleting / updating.
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}). * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}).
*/ */
public PreparedStatement prepareStatement(String sql, String[] columnNames) public PreparedStatement prepareStatement(String sql, final String[] columnNames) {
throws SQLException, HibernateException {
checkAutoGeneratedKeysSupportEnabled(); checkAutoGeneratedKeysSupportEnabled();
executeBatch(); StatementPreparer statementPreparer = new StatementPreparer( sql ) {
return proxiedConnection.prepareStatement( getSQL( sql ), columnNames ); public PreparedStatement doPrepare() throws SQLException {
return proxiedConnection.prepareStatement( getSqlToPrepare(), columnNames );
}
};
return prepareStatement( statementPreparer, true );
} }
private void checkAutoGeneratedKeysSupportEnabled() { private void checkAutoGeneratedKeysSupportEnabled() {
@ -424,28 +467,50 @@ public class ConnectionManagerImpl implements ConnectionManager {
* Get a non-batchable prepared statement to use for selecting. Does not * Get a non-batchable prepared statement to use for selecting. Does not
* result in execution of the current batch. * result in execution of the current batch.
*/ */
public PreparedStatement prepareSelectStatement(String sql) public PreparedStatement prepareSelectStatement(String sql) {
throws SQLException, HibernateException { return prepareStatement( sql, false, false );
return proxiedConnection.prepareStatement( getSQL( sql ) );
} }
/** /**
* Get a non-batchable prepared statement to use for inserting / deleting / updating. * Get a non-batchable prepared statement to use for inserting / deleting / updating.
*/ */
public PreparedStatement prepareStatement(String sql, boolean isCallable) public PreparedStatement prepareStatement(String sql, final boolean isCallable) {
throws SQLException, HibernateException { return prepareStatement( sql, isCallable, true );
return isCallable ? prepareCallableStatement( sql ) : prepareStatement( sql );
} }
/** /**
* Get a non-batchable callable statement to use for inserting / deleting / updating. * Get a non-batchable callable statement to use for inserting / deleting / updating.
*/ */
public CallableStatement prepareCallableStatement(String sql) throws SQLException, HibernateException { public CallableStatement prepareCallableStatement(String sql) {
executeBatch();
log.trace("preparing callable statement"); log.trace("preparing callable statement");
return CallableStatement.class.cast( return CallableStatement.class.cast( prepareStatement( sql, true, true ) );
proxiedConnection.prepareStatement( getSQL( sql ) ) }
);
public PreparedStatement prepareStatement(String sql, final boolean isCallable, boolean forceExecuteBatch) {
StatementPreparer statementPreparer = new StatementPreparer( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return prepareStatementInternal( getSqlToPrepare(), isCallable );
}
};
return prepareStatement( statementPreparer, forceExecuteBatch );
}
private PreparedStatement prepareStatementInternal(String sql, boolean isCallable) throws SQLException {
return isCallable ?
proxiedConnection.prepareCall( sql ) :
proxiedConnection.prepareStatement( sql );
}
private PreparedStatement prepareScrollableStatementInternal(String sql,
ScrollMode scrollMode,
boolean isCallable) throws SQLException {
return isCallable ?
proxiedConnection.prepareCall(
sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY
) :
proxiedConnection.prepareStatement(
sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY
);
} }
/** /**
@ -455,12 +520,12 @@ public class ConnectionManagerImpl implements ConnectionManager {
* statement explicitly. * statement explicitly.
* @see org.hibernate.jdbc.Batcher#addToBatch * @see org.hibernate.jdbc.Batcher#addToBatch
*/ */
public PreparedStatement prepareBatchStatement(String sql, boolean isCallable) public PreparedStatement prepareBatchStatement(String sql, boolean isCallable) {
throws SQLException, HibernateException {
String batchUpdateSQL = getSQL( sql ); String batchUpdateSQL = getSQL( sql );
PreparedStatement batchUpdate = getBatcher().getStatement( batchUpdateSQL ); PreparedStatement batchUpdate = getBatcher().getStatement( batchUpdateSQL );
if ( batchUpdate == null ) { if ( batchUpdate == null ) {
batchUpdate = prepareStatement( batchUpdateSQL, isCallable ); // calls executeBatch() batchUpdate = prepareStatement( batchUpdateSQL, isCallable, true ); // calls executeBatch()
getBatcher().setStatement( batchUpdateSQL, batchUpdate ); getBatcher().setStatement( batchUpdateSQL, batchUpdate );
} }
else { else {
@ -474,12 +539,6 @@ public class ConnectionManagerImpl implements ConnectionManager {
return logicalConnection.getBatcher(); return logicalConnection.getBatcher();
} }
private PreparedStatement prepareStatement(String sql)
throws SQLException, HibernateException {
executeBatch();
return proxiedConnection.prepareStatement( getSQL( sql ) );
}
/** /**
* Get a prepared statement for use in loading / querying. If not explicitly * Get a prepared statement for use in loading / querying. If not explicitly
* released by <tt>closeQueryStatement()</tt>, it will be released when the * released by <tt>closeQueryStatement()</tt>, it will be released when the
@ -487,16 +546,52 @@ public class ConnectionManagerImpl implements ConnectionManager {
*/ */
public PreparedStatement prepareQueryStatement( public PreparedStatement prepareQueryStatement(
String sql, String sql,
boolean isCallable) throws SQLException, HibernateException { final boolean isScrollable,
sql = getSQL( sql ); final ScrollMode scrollMode,
PreparedStatement result = ( final boolean isCallable
isCallable ? ) {
proxiedConnection.prepareCall(sql ) : if ( isScrollable && ! factory.getSettings().isScrollableResultSetsEnabled() ) {
proxiedConnection.prepareStatement( sql ) throw new AssertionFailure("scrollable result sets are not enabled");
); }
setStatementFetchSize( result ); StatementPreparer statementPreparer = new StatementPreparer( sql ) {
logicalConnection.getResourceRegistry().registerLastQuery( result ); public PreparedStatement doPrepare() throws SQLException {
return result; PreparedStatement ps =
isScrollable ?
prepareScrollableStatementInternal( getSqlToPrepare(), scrollMode, isCallable ) :
prepareStatementInternal( getSqlToPrepare(), isCallable )
;
return ps;
}
public void afterPrepare(PreparedStatement preparedStatement) throws SQLException {
super.afterPrepare( preparedStatement );
setStatementFetchSize( preparedStatement, getSqlToPrepare() );
logicalConnection.getResourceRegistry().registerLastQuery( preparedStatement );
}
};
return prepareStatement( statementPreparer, false );
}
private void setStatementFetchSize(PreparedStatement statement, String sql) throws SQLException {
if ( factory.getSettings().getJdbcFetchSize() != null ) {
statement.setFetchSize( factory.getSettings().getJdbcFetchSize() );
}
}
private PreparedStatement prepareStatement(StatementPreparer preparer, boolean forceExecuteBatch) {
if ( forceExecuteBatch ) {
executeBatch();
}
try {
PreparedStatement ps = preparer.doPrepare();
preparer.afterPrepare( ps );
return ps;
}
catch ( SQLException sqle ) {
log.error( "sqlexception escaped proxy", sqle );
throw logicalConnection.getJdbcServices().getSqlExceptionHelper().convert(
sqle, "could not prepare statement", preparer.getSqlToPrepare()
);
}
} }
/** /**
@ -506,34 +601,18 @@ public class ConnectionManagerImpl implements ConnectionManager {
logicalConnection.getResourceRegistry().cancelLastQuery(); logicalConnection.getResourceRegistry().cancelLastQuery();
} }
public PreparedStatement prepareScrollableQueryStatement(
String sql,
ScrollMode scrollMode,
boolean isCallable) throws SQLException, HibernateException {
if ( ! factory.getSettings().isScrollableResultSetsEnabled() ) {
throw new AssertionFailure("scrollable result sets are not enabled");
}
sql = getSQL( sql );
PreparedStatement result = (
isCallable ?
proxiedConnection.prepareCall(
sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY
) :
proxiedConnection.prepareStatement(
sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY
)
);
setStatementFetchSize( result );
logicalConnection.getResourceRegistry().registerLastQuery( result );
return result;
}
public void abortBatch(SQLException sqle) { public void abortBatch(SQLException sqle) {
getBatcher().abortBatch( sqle ); getBatcher().abortBatch( sqle );
} }
public void addToBatch(Expectation expectation ) throws SQLException, HibernateException { public void addToBatch(Expectation expectation ) {
getBatcher().addToBatch( expectation ); try {
getBatcher().addToBatch( expectation );
}
catch (SQLException sqle) {
throw logicalConnection.getJdbcServices().getSqlExceptionHelper().convert(
sqle, "could not add to batch statement" );
}
} }
public void executeBatch() throws HibernateException { public void executeBatch() throws HibernateException {
@ -548,12 +627,6 @@ public class ConnectionManagerImpl implements ConnectionManager {
return sql; return sql;
} }
private void setStatementFetchSize(PreparedStatement statement) throws SQLException {
if ( factory.getSettings().getJdbcFetchSize() !=null ) {
statement.setFetchSize( factory.getSettings().getJdbcFetchSize().intValue() );
}
}
public boolean isReadyForSerialization() { public boolean isReadyForSerialization() {
return logicalConnection == null ? true : logicalConnection.isReadyForSerialization(); return logicalConnection == null ? true : logicalConnection.isReadyForSerialization();
} }

View File

@ -64,8 +64,6 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
private final List<ConnectionObserver> observers = new ArrayList<ConnectionObserver>(); private final List<ConnectionObserver> observers = new ArrayList<ConnectionObserver>();
private boolean releasesEnabled = true; private boolean releasesEnabled = true;
private long transactionTimeout = -1;
boolean isTransactionTimeoutSet;
private final boolean isUserSuppliedConnection; private final boolean isUserSuppliedConnection;
@ -132,40 +130,6 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
} }
} }
/**
* Set the transaction timeout to <tt>seconds</tt> later
* than the current system time.
*/
public void setTransactionTimeout(int seconds) {
isTransactionTimeoutSet = true;
transactionTimeout = System.currentTimeMillis() / 1000 + seconds;
}
/**
* Unset the transaction timeout, called after the end of a
* transaction.
*/
private void unsetTransactionTimeout() {
isTransactionTimeoutSet = false;
}
/**
* {@inheritDoc}
*/
public boolean isTransactionTimeoutSet() {
return isTransactionTimeoutSet;
}
/**
* {@inheritDoc}
*/
public long getTransactionTimeout() throws HibernateException {
if ( isTransactionTimeoutSet ) {
throw new HibernateException( "transaction timeout has not been set." );
}
return transactionTimeout;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -327,7 +291,6 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
} }
aggressiveRelease(); aggressiveRelease();
} }
unsetTransactionTimeout();
} }
public void disableReleases() { public void disableReleases() {

View File

@ -181,7 +181,6 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
} }
private void postProcessStatement(Statement statement) throws SQLException { private void postProcessStatement(Statement statement) throws SQLException {
setTimeout( statement );
getResourceRegistry().register( statement ); getResourceRegistry().register( statement );
} }
@ -229,18 +228,4 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
StatisticsImplementor getStatisticsImplementorOrNull() { StatisticsImplementor getStatisticsImplementorOrNull() {
return getLogicalConnection().getStatisticsImplementor(); return getLogicalConnection().getStatisticsImplementor();
} }
private void setTimeout(Statement result) throws SQLException {
if ( logicalConnection.isTransactionTimeoutSet() ) {
int timeout = (int) ( logicalConnection.getTransactionTimeout() - ( System.currentTimeMillis() / 1000 ) );
if (timeout<=0) {
throw new TransactionException("transaction timeout expired");
}
else {
result.setQueryTimeout(timeout);
}
}
}
} }

View File

@ -55,7 +55,7 @@ public interface ConnectionManager extends Serializable {
* @throws HibernateException Indicates a connection is currently not * @throws HibernateException Indicates a connection is currently not
* available (we are currently manually disconnected). * available (we are currently manually disconnected).
*/ */
Connection getConnection() throws HibernateException; Connection getConnection();
// TODO: should this be removd from the SPI? // TODO: should this be removd from the SPI?
boolean hasBorrowedConnection(); boolean hasBorrowedConnection();
@ -132,33 +132,29 @@ public interface ConnectionManager extends Serializable {
* Get a non-batchable prepared statement to use for inserting / deleting / updating, * Get a non-batchable prepared statement to use for inserting / deleting / updating,
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}). * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}).
*/ */
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys);
throws SQLException, HibernateException;
/** /**
* Get a non-batchable prepared statement to use for inserting / deleting / updating. * Get a non-batchable prepared statement to use for inserting / deleting / updating.
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}). * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}).
*/ */
public PreparedStatement prepareStatement(String sql, String[] columnNames) public PreparedStatement prepareStatement(String sql, String[] columnNames);
throws SQLException, HibernateException;
/** /**
* Get a non-batchable prepared statement to use for selecting. Does not * Get a non-batchable prepared statement to use for selecting. Does not
* result in execution of the current batch. * result in execution of the current batch.
*/ */
public PreparedStatement prepareSelectStatement(String sql) public PreparedStatement prepareSelectStatement(String sql);
throws SQLException, HibernateException;
/** /**
* Get a non-batchable prepared statement to use for inserting / deleting / updating. * Get a non-batchable prepared statement to use for inserting / deleting / updating.
*/ */
public PreparedStatement prepareStatement(String sql, boolean isCallable) public PreparedStatement prepareStatement(String sql, boolean isCallable);
throws SQLException, HibernateException ;
/** /**
* Get a non-batchable callable statement to use for inserting / deleting / updating. * Get a non-batchable callable statement to use for inserting / deleting / updating.
*/ */
public CallableStatement prepareCallableStatement(String sql) throws SQLException, HibernateException; public CallableStatement prepareCallableStatement(String sql);
/** /**
* Get a batchable prepared statement to use for inserting / deleting / updating * Get a batchable prepared statement to use for inserting / deleting / updating
@ -167,7 +163,7 @@ public interface ConnectionManager extends Serializable {
* statement explicitly. * statement explicitly.
* @see org.hibernate.jdbc.Batcher#addToBatch * @see org.hibernate.jdbc.Batcher#addToBatch
*/ */
public PreparedStatement prepareBatchStatement(String sql, boolean isCallable) throws SQLException, HibernateException; public PreparedStatement prepareBatchStatement(String sql, boolean isCallable);
/** /**
* Get a prepared statement for use in loading / querying. If not explicitly * Get a prepared statement for use in loading / querying. If not explicitly
@ -176,20 +172,17 @@ public interface ConnectionManager extends Serializable {
*/ */
public PreparedStatement prepareQueryStatement( public PreparedStatement prepareQueryStatement(
String sql, String sql,
boolean isCallable) throws SQLException, HibernateException; boolean isScrollable,
ScrollMode scrollMode,
boolean isCallable);
/** /**
* Cancel the current query statement * Cancel the current query statement
*/ */
public void cancelLastQuery() throws HibernateException; public void cancelLastQuery();
public PreparedStatement prepareScrollableQueryStatement(
String sql,
ScrollMode scrollMode,
boolean isCallable) throws SQLException, HibernateException;
public void abortBatch(SQLException sqle); public void abortBatch(SQLException sqle);
public void addToBatch(Expectation expectation ) throws SQLException, HibernateException; public void addToBatch(Expectation expectation );
public void executeBatch() throws HibernateException; public void executeBatch();
} }

View File

@ -46,20 +46,6 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
*/ */
public StatisticsImplementor getStatisticsImplementor(); public StatisticsImplementor getStatisticsImplementor();
/**
* Is the transaction timeout set?
*
* @return true, if the transaction timeout is set; false otherwise
*/
public boolean isTransactionTimeoutSet();
/**
* Gets the transaction timeout.
*
* @return the transaction time out
*/
public long getTransactionTimeout();
/** /**
* Obtains the JDBC resource registry associated with this logical connection. * Obtains the JDBC resource registry associated with this logical connection.
* *

View File

@ -1749,10 +1749,11 @@ public abstract class Loader {
PreparedStatement st = null; PreparedStatement st = null;
st = ( st = session.getJDBCContext().getConnectionManager().prepareQueryStatement(
scroll || useScrollableResultSetToSkip ? sql,
session.getJDBCContext().getConnectionManager().prepareScrollableQueryStatement( sql, scrollMode, callable ) : scroll || useScrollableResultSetToSkip,
session.getJDBCContext().getConnectionManager().prepareQueryStatement( sql, callable ) scrollMode,
callable
); );
try { try {