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.Interceptor;
import org.hibernate.ScrollMode;
import org.hibernate.TransactionException;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
import org.hibernate.engine.jdbc.spi.ConnectionManager;
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
import org.hibernate.engine.jdbc.spi.LogicalConnection;
import org.hibernate.jdbc.Batcher;
import org.hibernate.jdbc.Expectation;
@ -72,6 +72,8 @@ public class ConnectionManagerImpl implements ConnectionManager {
private transient Interceptor interceptor;
private final Callback callback;
private long transactionTimeout = -1;
boolean isTransactionTimeoutSet;
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!" );
}
}
unsetTransactionTimeout();
}
private boolean isAfterTransactionRelease() {
@ -285,9 +288,31 @@ public class ConnectionManagerImpl implements ConnectionManager {
@Override
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
* connection.
@ -387,31 +412,49 @@ public class ConnectionManagerImpl implements ConnectionManager {
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,
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}).
*/
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
throws SQLException, HibernateException {
public PreparedStatement prepareStatement(String sql, final int autoGeneratedKeys)
throws HibernateException {
if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) {
checkAutoGeneratedKeysSupportEnabled();
}
executeBatch();
return proxiedConnection.prepareStatement(
getSQL( sql ),
autoGeneratedKeys
);
StatementPreparer statementPreparer = new StatementPreparer( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return proxiedConnection.prepareStatement( getSqlToPrepare(), autoGeneratedKeys );
}
};
return prepareStatement( statementPreparer, true );
}
/**
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}).
*/
public PreparedStatement prepareStatement(String sql, String[] columnNames)
throws SQLException, HibernateException {
public PreparedStatement prepareStatement(String sql, final String[] columnNames) {
checkAutoGeneratedKeysSupportEnabled();
executeBatch();
return proxiedConnection.prepareStatement( getSQL( sql ), columnNames );
StatementPreparer statementPreparer = new StatementPreparer( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return proxiedConnection.prepareStatement( getSqlToPrepare(), columnNames );
}
};
return prepareStatement( statementPreparer, true );
}
private void checkAutoGeneratedKeysSupportEnabled() {
@ -424,28 +467,50 @@ public class ConnectionManagerImpl implements ConnectionManager {
* Get a non-batchable prepared statement to use for selecting. Does not
* result in execution of the current batch.
*/
public PreparedStatement prepareSelectStatement(String sql)
throws SQLException, HibernateException {
return proxiedConnection.prepareStatement( getSQL( sql ) );
public PreparedStatement prepareSelectStatement(String sql) {
return prepareStatement( sql, false, false );
}
/**
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
*/
public PreparedStatement prepareStatement(String sql, boolean isCallable)
throws SQLException, HibernateException {
return isCallable ? prepareCallableStatement( sql ) : prepareStatement( sql );
public PreparedStatement prepareStatement(String sql, final boolean isCallable) {
return prepareStatement( sql, isCallable, true );
}
/**
* Get a non-batchable callable statement to use for inserting / deleting / updating.
*/
public CallableStatement prepareCallableStatement(String sql) throws SQLException, HibernateException {
executeBatch();
public CallableStatement prepareCallableStatement(String sql) {
log.trace("preparing callable statement");
return CallableStatement.class.cast(
proxiedConnection.prepareStatement( getSQL( sql ) )
);
return CallableStatement.class.cast( prepareStatement( sql, true, true ) );
}
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.
* @see org.hibernate.jdbc.Batcher#addToBatch
*/
public PreparedStatement prepareBatchStatement(String sql, boolean isCallable)
throws SQLException, HibernateException {
public PreparedStatement prepareBatchStatement(String sql, boolean isCallable) {
String batchUpdateSQL = getSQL( sql );
PreparedStatement batchUpdate = getBatcher().getStatement( batchUpdateSQL );
if ( batchUpdate == null ) {
batchUpdate = prepareStatement( batchUpdateSQL, isCallable ); // calls executeBatch()
batchUpdate = prepareStatement( batchUpdateSQL, isCallable, true ); // calls executeBatch()
getBatcher().setStatement( batchUpdateSQL, batchUpdate );
}
else {
@ -474,12 +539,6 @@ public class ConnectionManagerImpl implements ConnectionManager {
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
* released by <tt>closeQueryStatement()</tt>, it will be released when the
@ -487,16 +546,52 @@ public class ConnectionManagerImpl implements ConnectionManager {
*/
public PreparedStatement prepareQueryStatement(
String sql,
boolean isCallable) throws SQLException, HibernateException {
sql = getSQL( sql );
PreparedStatement result = (
isCallable ?
proxiedConnection.prepareCall(sql ) :
proxiedConnection.prepareStatement( sql )
);
setStatementFetchSize( result );
logicalConnection.getResourceRegistry().registerLastQuery( result );
return result;
final boolean isScrollable,
final ScrollMode scrollMode,
final boolean isCallable
) {
if ( isScrollable && ! factory.getSettings().isScrollableResultSetsEnabled() ) {
throw new AssertionFailure("scrollable result sets are not enabled");
}
StatementPreparer statementPreparer = new StatementPreparer( sql ) {
public PreparedStatement doPrepare() throws SQLException {
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();
}
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) {
getBatcher().abortBatch( sqle );
}
public void addToBatch(Expectation expectation ) throws SQLException, HibernateException {
getBatcher().addToBatch( expectation );
public void addToBatch(Expectation 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 {
@ -548,12 +627,6 @@ public class ConnectionManagerImpl implements ConnectionManager {
return sql;
}
private void setStatementFetchSize(PreparedStatement statement) throws SQLException {
if ( factory.getSettings().getJdbcFetchSize() !=null ) {
statement.setFetchSize( factory.getSettings().getJdbcFetchSize().intValue() );
}
}
public boolean 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 boolean releasesEnabled = true;
private long transactionTimeout = -1;
boolean isTransactionTimeoutSet;
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}
*/
@ -327,7 +291,6 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
}
aggressiveRelease();
}
unsetTransactionTimeout();
}
public void disableReleases() {

View File

@ -181,7 +181,6 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
}
private void postProcessStatement(Statement statement) throws SQLException {
setTimeout( statement );
getResourceRegistry().register( statement );
}
@ -229,18 +228,4 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
StatisticsImplementor getStatisticsImplementorOrNull() {
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
* available (we are currently manually disconnected).
*/
Connection getConnection() throws HibernateException;
Connection getConnection();
// TODO: should this be removd from the SPI?
boolean hasBorrowedConnection();
@ -132,33 +132,29 @@ public interface ConnectionManager extends Serializable {
* Get a non-batchable prepared statement to use for inserting / deleting / updating,
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}).
*/
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
throws SQLException, HibernateException;
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys);
/**
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}).
*/
public PreparedStatement prepareStatement(String sql, String[] columnNames)
throws SQLException, HibernateException;
public PreparedStatement prepareStatement(String sql, String[] columnNames);
/**
* Get a non-batchable prepared statement to use for selecting. Does not
* result in execution of the current batch.
*/
public PreparedStatement prepareSelectStatement(String sql)
throws SQLException, HibernateException;
public PreparedStatement prepareSelectStatement(String sql);
/**
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
*/
public PreparedStatement prepareStatement(String sql, boolean isCallable)
throws SQLException, HibernateException ;
public PreparedStatement prepareStatement(String sql, boolean isCallable);
/**
* 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
@ -167,7 +163,7 @@ public interface ConnectionManager extends Serializable {
* statement explicitly.
* @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
@ -176,20 +172,17 @@ public interface ConnectionManager extends Serializable {
*/
public PreparedStatement prepareQueryStatement(
String sql,
boolean isCallable) throws SQLException, HibernateException;
boolean isScrollable,
ScrollMode scrollMode,
boolean isCallable);
/**
* Cancel the current query statement
*/
public void cancelLastQuery() throws HibernateException;
public PreparedStatement prepareScrollableQueryStatement(
String sql,
ScrollMode scrollMode,
boolean isCallable) throws SQLException, HibernateException;
public void cancelLastQuery();
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();
/**
* 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.
*

View File

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