FileDocCategorySizeDatePackage
AbstractBatcher.javaAPI DocHibernate 3.2.515957Thu Mar 22 11:35:22 GMT 2007org.hibernate.jdbc

AbstractBatcher

public abstract class AbstractBatcher extends Object implements Batcher
Manages prepared statements and batching.
author
Gavin King

Fields Summary
private static int
globalOpenPreparedStatementCount
private static int
globalOpenResultSetCount
private int
openPreparedStatementCount
private int
openResultSetCount
protected static final Log
log
protected static final Log
SQL_LOG
private final ConnectionManager
connectionManager
private final org.hibernate.engine.SessionFactoryImplementor
factory
private PreparedStatement
batchUpdate
private String
batchUpdateSQL
private HashSet
statementsToClose
private HashSet
resultSetsToClose
private PreparedStatement
lastQuery
private boolean
releasing
private final org.hibernate.Interceptor
interceptor
private long
transactionTimeout
boolean
isTransactionTimeoutSet
Constructors Summary
public AbstractBatcher(ConnectionManager connectionManager, org.hibernate.Interceptor interceptor)


	     
		this.connectionManager = connectionManager;
		this.interceptor = interceptor;
		this.factory = connectionManager.getFactory();
	
Methods Summary
public voidabortBatch(java.sql.SQLException sqle)

		try {
			if (batchUpdate!=null) closeStatement(batchUpdate);
		}
		catch (SQLException e) {
			//noncritical, swallow and let the other propagate!
			JDBCExceptionReporter.logExceptions(e);
		}
		finally {
			batchUpdate=null;
			batchUpdateSQL=null;
		}
	
public voidcancelLastQuery()

		try {
			if (lastQuery!=null) lastQuery.cancel();
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert(
					factory.getSQLExceptionConverter(),
			        sqle,
			        "Cannot cancel query"
				);
		}
	
public voidcloseConnection(java.sql.Connection conn)

		if ( log.isDebugEnabled() ) {
			log.debug(
					"closing JDBC connection" +
					preparedStatementCountsToString() +
					resultSetCountsToString()
				);
		}

		try {
			if ( !conn.isClosed() ) {
				JDBCExceptionReporter.logAndClearWarnings(conn);
			}
			factory.getConnectionProvider().closeConnection(conn);
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert(
					factory.getSQLExceptionConverter(),
			        sqle,
			        "Cannot close connection"
				);
		}
	
private voidclosePreparedStatement(java.sql.PreparedStatement ps)

		try {
			log.trace("closing statement");
			ps.close();
			if ( factory.getStatistics().isStatisticsEnabled() ) {
				factory.getStatisticsImplementor().closeStatement();
			}
		}
		finally {
			if ( !releasing ) {
				// If we are in the process of releasing, no sense
				// checking for aggressive-release possibility.
				connectionManager.afterStatement();
			}
		}
	
public voidcloseQueryStatement(java.sql.PreparedStatement ps, java.sql.ResultSet rs)

		boolean psStillThere = statementsToClose.remove( ps );
		try {
			if ( rs != null ) {
				if ( resultSetsToClose.remove( rs ) ) {
					logCloseResults();
					rs.close();
				}
			}
		}
		finally {
			if ( psStillThere ) {
				closeQueryStatement( ps );
			}
		}
	
private voidcloseQueryStatement(java.sql.PreparedStatement ps)


		try {
			//work around a bug in all known connection pools....
			if ( ps.getMaxRows()!=0 ) ps.setMaxRows(0);
			if ( ps.getQueryTimeout()!=0 ) ps.setQueryTimeout(0);
		}
		catch (Exception e) {
			log.warn("exception clearing maxRows/queryTimeout", e);
//			ps.close(); //just close it; do NOT try to return it to the pool!
			return; //NOTE: early exit!
		}
		finally {
			closeStatement(ps);
		}

		if ( lastQuery==ps ) lastQuery = null;

	
public voidcloseStatement(java.sql.PreparedStatement ps)

		logClosePreparedStatement();
		closePreparedStatement(ps);
	
public voidcloseStatements()
Actually releases the batcher, allowing it to cleanup internally held resources.

		try {
			releasing = true;

			try {
				if (batchUpdate!=null) batchUpdate.close();
			}
			catch (SQLException sqle) {
				//no big deal
				log.warn("Could not close a JDBC prepared statement", sqle);
			}
			batchUpdate=null;
			batchUpdateSQL=null;

			Iterator iter = resultSetsToClose.iterator();
			while ( iter.hasNext() ) {
				try {
					logCloseResults();
					( (ResultSet) iter.next() ).close();
				}
				catch (SQLException e) {
					// no big deal
					log.warn("Could not close a JDBC result set", e);
				}
				catch (Throwable e) {
					// sybase driver (jConnect) throwing NPE here in certain cases
					log.warn("Could not close a JDBC result set", e);
				}
			}
			resultSetsToClose.clear();

			iter = statementsToClose.iterator();
			while ( iter.hasNext() ) {
				try {
					closeQueryStatement( (PreparedStatement) iter.next() );
				}
				catch (SQLException e) {
					// no big deal
					log.warn("Could not close a JDBC statement", e);
				}
			}
			statementsToClose.clear();
		}
		finally {
			releasing = false;
		}
	
protected abstract voiddoExecuteBatch(java.sql.PreparedStatement ps)

public voidexecuteBatch()

		if (batchUpdate!=null) {
			try {
				try {
					doExecuteBatch(batchUpdate);
				}
				finally {
					closeStatement(batchUpdate);
				}
			}
			catch (SQLException sqle) {
				throw JDBCExceptionHelper.convert(
				        factory.getSQLExceptionConverter(),
				        sqle,
				        "Could not execute JDBC batch update",
				        batchUpdateSQL
					);
			}
			finally {
				batchUpdate=null;
				batchUpdateSQL=null;
			}
		}
	
private java.lang.Stringformat(java.lang.String sql)

		if ( factory.getSettings().isFormatSqlEnabled() ) {
			return new Formatter(sql).format();
		}
		else {
			return sql;
		}
	
private java.sql.CallableStatementgetCallableStatement(java.sql.Connection conn, java.lang.String sql, boolean scrollable)

		if ( scrollable && !factory.getSettings().isScrollableResultSetsEnabled() ) {
			throw new AssertionFailure("scrollable result sets are not enabled");
		}

		sql = getSQL( sql );
		log( sql );

		log.trace("preparing callable statement");
		if ( scrollable ) {
			return conn.prepareCall(
					sql,
			        ResultSet.TYPE_SCROLL_INSENSITIVE,
			        ResultSet.CONCUR_READ_ONLY
			);
		}
		else {
			return conn.prepareCall( sql );
		}
	
protected org.hibernate.engine.SessionFactoryImplementorgetFactory()

		return factory;
	
private java.sql.PreparedStatementgetPreparedStatement(java.sql.Connection conn, java.lang.String sql, boolean scrollable, org.hibernate.ScrollMode scrollMode)

		return getPreparedStatement(
				conn,
		        sql,
		        scrollable,
		        false,
		        null,
		        scrollMode,
		        false
		);
	
private java.sql.PreparedStatementgetPreparedStatement(java.sql.Connection conn, java.lang.String sql, boolean scrollable, boolean useGetGeneratedKeys, java.lang.String[] namedGeneratedKeys, org.hibernate.ScrollMode scrollMode, boolean callable)

		if ( scrollable && !factory.getSettings().isScrollableResultSetsEnabled() ) {
			throw new AssertionFailure("scrollable result sets are not enabled");
		}
		if ( useGetGeneratedKeys && !factory.getSettings().isGetGeneratedKeysEnabled() ) {
			throw new AssertionFailure("getGeneratedKeys() support is not enabled");
		}

		sql = getSQL( sql );
		log( sql );

		log.trace( "preparing statement" );
		PreparedStatement result;
		if ( scrollable ) {
			if ( callable ) {
				result = conn.prepareCall( sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY );
			}
			else {
				result = conn.prepareStatement( sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY );
			}
		}
		else if ( useGetGeneratedKeys ) {
			result = GetGeneratedKeysHelper.prepareStatement( conn, sql );
		}
		else if ( namedGeneratedKeys != null ) {
			result = NamedGeneratedKeysHelper.prepareStatement( conn, sql, namedGeneratedKeys );
		}
		else {
			if ( callable ) {
				result = conn.prepareCall( sql );
			}
			else {
				result = conn.prepareStatement( sql );
			}
		}

		setTimeout( result );

		if ( factory.getStatistics().isStatisticsEnabled() ) {
			factory.getStatisticsImplementor().prepareStatement();
		}

		return result;

	
public java.sql.ResultSetgetResultSet(java.sql.PreparedStatement ps)

		ResultSet rs = ps.executeQuery();
		resultSetsToClose.add(rs);
		logOpenResults();
		return rs;
	
public java.sql.ResultSetgetResultSet(java.sql.CallableStatement ps, org.hibernate.dialect.Dialect dialect)

		ResultSet rs = dialect.getResultSet(ps);
		resultSetsToClose.add(rs);
		logOpenResults();
		return rs;

	
private java.lang.StringgetSQL(java.lang.String sql)

		sql = interceptor.onPrepareStatement( sql );
		if ( sql==null || sql.length() == 0 ) {
			throw new AssertionFailure( "Interceptor.onPrepareStatement() returned null or empty string." );
		}
		return sql;
	
protected java.sql.PreparedStatementgetStatement()

		return batchUpdate;
	
public booleanhasOpenResources()

		return resultSetsToClose.size() > 0 || statementsToClose.size() > 0;
	
private voidlog(java.lang.String sql)

		if ( SQL_LOG.isDebugEnabled() ) {
			SQL_LOG.debug( format(sql) );
		}
		if ( factory.getSettings().isShowSqlEnabled() ) {
			System.out.println( "Hibernate: " + format(sql) );
		}
	
private voidlogClosePreparedStatement()

		if ( log.isDebugEnabled() ) {
			log.debug( "about to close PreparedStatement" + preparedStatementCountsToString() );
			openPreparedStatementCount--;
			globalOpenPreparedStatementCount--;
		}
	
private voidlogCloseResults()

		if ( log.isDebugEnabled() ) {
			log.debug( "about to close ResultSet" + resultSetCountsToString() );
			openResultSetCount--;
			globalOpenResultSetCount--;
		}
	
private voidlogOpenPreparedStatement()

		if ( log.isDebugEnabled() ) {
			log.debug( "about to open PreparedStatement" + preparedStatementCountsToString() );
			openPreparedStatementCount++;
			globalOpenPreparedStatementCount++;
		}
	
private voidlogOpenResults()

		if ( log.isDebugEnabled() ) {
			log.debug( "about to open ResultSet" + resultSetCountsToString() );
			openResultSetCount++;
			globalOpenResultSetCount++;
		}
	
public java.sql.ConnectionopenConnection()

		log.debug("opening JDBC connection");
		try {
			return factory.getConnectionProvider().getConnection();
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert(
					factory.getSQLExceptionConverter(),
			        sqle,
			        "Cannot open connection"
				);
		}
	
public java.lang.StringopenResourceStatsAsString()

		return preparedStatementCountsToString() + resultSetCountsToString();
	
public java.sql.CallableStatementprepareBatchCallableStatement(java.lang.String sql)

		if ( !sql.equals(batchUpdateSQL) ) { // TODO: what if batchUpdate is a callablestatement ?
			batchUpdate=prepareCallableStatement(sql); // calls executeBatch()
			batchUpdateSQL=sql;
		}
		return (CallableStatement)batchUpdate;
	
public java.sql.PreparedStatementprepareBatchStatement(java.lang.String sql)

		sql = getSQL( sql );

		if ( !sql.equals(batchUpdateSQL) ) {
			batchUpdate=prepareStatement(sql); // calls executeBatch()
			batchUpdateSQL=sql;
		}
		else {
			log.debug("reusing prepared statement");
			log(sql);
		}
		return batchUpdate;
	
public java.sql.CallableStatementprepareCallableQueryStatement(java.lang.String sql, boolean scrollable, org.hibernate.ScrollMode scrollMode)

		logOpenPreparedStatement();
		CallableStatement ps = ( CallableStatement ) getPreparedStatement(
				connectionManager.getConnection(),
		        sql,
		        scrollable,
		        false,
		        null,
		        scrollMode,
		        true
		);
		setStatementFetchSize( ps );
		statementsToClose.add( ps );
		lastQuery = ps;
		return ps;
	
public java.sql.CallableStatementprepareCallableStatement(java.lang.String sql)

		executeBatch();
		logOpenPreparedStatement();
		return getCallableStatement( connectionManager.getConnection(), sql, false);
	
public java.sql.PreparedStatementprepareQueryStatement(java.lang.String sql, boolean scrollable, org.hibernate.ScrollMode scrollMode)

		logOpenPreparedStatement();
		PreparedStatement ps = getPreparedStatement(
				connectionManager.getConnection(),
		        sql,
		        scrollable,
		        scrollMode
		);
		setStatementFetchSize( ps );
		statementsToClose.add( ps );
		lastQuery = ps;
		return ps;
	
public java.sql.PreparedStatementprepareSelectStatement(java.lang.String sql)

		logOpenPreparedStatement();
		return getPreparedStatement(
				connectionManager.getConnection(),
		        sql,
		        false,
		        false,
		        null,
		        null,
		        false
		);
	
public java.sql.PreparedStatementprepareStatement(java.lang.String sql)

		return prepareStatement( sql, false );
	
public java.sql.PreparedStatementprepareStatement(java.lang.String sql, boolean getGeneratedKeys)

		executeBatch();
		logOpenPreparedStatement();
		return getPreparedStatement(
				connectionManager.getConnection(),
		        sql,
		        false,
		        getGeneratedKeys,
		        null,
		        null,
		        false
		);
	
public java.sql.PreparedStatementprepareStatement(java.lang.String sql, java.lang.String[] columnNames)

		executeBatch();
		logOpenPreparedStatement();
		return getPreparedStatement(
				connectionManager.getConnection(),
		        sql,
		        false,
		        false,
		        columnNames,
		        null,
		        false
		);
	
private java.lang.StringpreparedStatementCountsToString()

		return
				" (open PreparedStatements: " +
				openPreparedStatementCount +
				", globally: " +
				globalOpenPreparedStatementCount +
				")";
	
private java.lang.StringresultSetCountsToString()

		return
				" (open ResultSets: " +
				openResultSetCount +
				", globally: " +
				globalOpenResultSetCount +
				")";
	
private voidsetStatementFetchSize(java.sql.PreparedStatement statement)

		Integer statementFetchSize = factory.getSettings().getJdbcFetchSize();
		if ( statementFetchSize!=null ) {
			statement.setFetchSize( statementFetchSize.intValue() );
		}
	
private voidsetTimeout(java.sql.PreparedStatement result)

		if ( isTransactionTimeoutSet ) {
			int timeout = (int) ( transactionTimeout - ( System.currentTimeMillis() / 1000 ) );
			if (timeout<=0) {
				throw new TransactionException("transaction timeout expired");
			}
			else {
				result.setQueryTimeout(timeout);
			}
		}
	
public voidsetTransactionTimeout(int seconds)

		isTransactionTimeoutSet = true;
		transactionTimeout = System.currentTimeMillis() / 1000 + seconds;
	
public voidunsetTransactionTimeout()

		isTransactionTimeoutSet = false;