Merge branch 'HHH-5778-batch'

This commit is contained in:
Gail Badner 2010-12-16 23:59:10 -08:00
commit 66f8e90e7c
31 changed files with 776 additions and 990 deletions

View File

@ -32,7 +32,6 @@ import org.hibernate.cache.RegionFactory;
import org.hibernate.engine.jdbc.JdbcSupport;
import org.hibernate.engine.jdbc.batch.internal.BatchBuilder;
import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.jdbc.BatcherFactory;
import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.transaction.TransactionManagerLookup;
@ -78,7 +77,6 @@ public final class Settings {
private QueryCacheFactory queryCacheFactory;
private TransactionFactory transactionFactory;
private TransactionManagerLookup transactionManagerLookup;
private BatcherFactory batcherFactory;
private BatchBuilder batchBuilder;
private QueryTranslatorFactory queryTranslatorFactory;
private boolean wrapResultSetsEnabled;
@ -228,10 +226,6 @@ public final class Settings {
return flushBeforeCompletionEnabled;
}
public BatcherFactory getBatcherFactory() {
return batcherFactory;
}
public BatchBuilder getBatchBuilder() {
return batchBuilder;
}
@ -419,10 +413,6 @@ public final class Settings {
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
}
void setBatcherFactory(BatcherFactory batcher) {
this.batcherFactory = batcher;
}
void setBatcherBuilder(BatchBuilder batchBuilder) {
this.batchBuilder = batchBuilder;
}

View File

@ -44,9 +44,6 @@ import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jdbc.BatcherFactory;
import org.hibernate.jdbc.BatchingBatcherFactory;
import org.hibernate.jdbc.NonBatchingBatcherFactory;
import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.transaction.TransactionFactoryFactory;
@ -115,7 +112,6 @@ public class SettingsFactory implements Serializable {
boolean jdbcBatchVersionedData = ConfigurationHelper.getBoolean(Environment.BATCH_VERSIONED_DATA, properties, false);
if (batchSize>0) log.info("JDBC batch updates for versioned data: " + enabledDisabled(jdbcBatchVersionedData) );
settings.setJdbcBatchVersionedData(jdbcBatchVersionedData);
settings.setBatcherFactory( createBatcherFactory(properties, batchSize) );
settings.setBatcherBuilder( createBatchBuilder(properties, batchSize) );
boolean useScrollableResultSets = ConfigurationHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, meta.supportsScrollableResults());
@ -350,47 +346,25 @@ public class SettingsFactory implements Serializable {
}
}
protected BatcherFactory createBatcherFactory(Properties properties, int batchSize) {
String batcherClass = properties.getProperty(Environment.BATCH_STRATEGY);
BatcherFactory batcherFactory = null;
if (batcherClass==null) {
batcherFactory = batchSize == 0
? new NonBatchingBatcherFactory()
: new BatchingBatcherFactory( );
}
else {
log.info("Batcher factory: " + batcherClass);
try {
batcherFactory = (BatcherFactory) ReflectHelper.classForName(batcherClass).newInstance();
}
catch (Exception cnfe) {
throw new HibernateException("could not instantiate BatcherFactory: " + batcherClass, cnfe);
}
}
batcherFactory.setJdbcBatchSize( batchSize );
return batcherFactory;
}
protected BatchBuilder createBatchBuilder(Properties properties, int batchSize) {
//FIXME: uncomment to use BatchBuilder
/*
String batchBuilderClass = properties.getProperty(Environment.BATCH_STRATEGY);
BatchBuilder batchBuilder;
if (batchBuilderClass==null) {
return batchSize > 0
batchBuilder = batchSize > 0
? new BatchBuilder( batchSize )
: new BatchBuilder();
}
else {
log.info("Batcher factory: " + batchBuilderClass);
log.info("Batch factory: " + batchBuilderClass);
try {
return (BatchBuilder) ReflectHelper.classForName(batchBuilderClass).newInstance();
batchBuilder = (BatchBuilder) ReflectHelper.classForName(batchBuilderClass).newInstance();
}
catch (Exception cnfe) {
throw new HibernateException("could not instantiate BatchBuilder: " + batchBuilderClass, cnfe);
}
}
*/
return null;
batchBuilder.setJdbcBatchSize( batchSize );
return batchBuilder;
}
protected TransactionFactory createTransactionFactory(Properties properties) {

View File

@ -23,7 +23,6 @@
*/
package org.hibernate.engine.jdbc.batch.internal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedHashMap;
@ -34,9 +33,8 @@ import org.slf4j.LoggerFactory;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchObserver;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
/**
* Convenience base class for implementors of the Batch interface.
@ -46,16 +44,21 @@ import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
public abstract class AbstractBatchImpl implements Batch {
private static final Logger log = LoggerFactory.getLogger( AbstractBatchImpl.class );
private final SQLStatementLogger statementLogger;
private final SQLExceptionHelper exceptionHelper;
private Object key;
private LogicalConnectionImplementor logicalConnection;
private Connection connectionProxy;
private LinkedHashMap<String,PreparedStatement> statements = new LinkedHashMap<String,PreparedStatement>();
private LinkedHashSet<BatchObserver> observers = new LinkedHashSet<BatchObserver>();
protected AbstractBatchImpl(Object key, LogicalConnectionImplementor logicalConnection) {
protected AbstractBatchImpl(Object key,
SQLStatementLogger statementLogger,
SQLExceptionHelper exceptionHelper) {
if ( key == null || statementLogger == null || exceptionHelper == null ) {
throw new IllegalArgumentException( "key, statementLogger, and exceptionHelper must be non-null." );
}
this.key = key;
this.logicalConnection = logicalConnection;
this.connectionProxy = ProxyBuilder.buildConnection( logicalConnection );
this.statementLogger = statementLogger;
this.exceptionHelper = exceptionHelper;
}
/**
@ -67,12 +70,21 @@ public abstract class AbstractBatchImpl implements Batch {
protected abstract void doExecuteBatch();
/**
* Convenience access to the underlying JDBC services.
* Convenience access to the SQLException helper.
*
* @return The underlying SQLException helper.
*/
protected SQLExceptionHelper getSqlExceptionHelper() {
return exceptionHelper;
}
/**
* Convenience access to the SQL statement logger.
*
* @return The underlying JDBC services.
*/
protected JdbcServices getJdbcServices() {
return logicalConnection.getJdbcServices();
protected SQLStatementLogger getSqlStatementLogger() {
return statementLogger;
}
/**
@ -101,31 +113,39 @@ public abstract class AbstractBatchImpl implements Batch {
/**
* {@inheritDoc}
*/
public final PreparedStatement getBatchStatement(String sql, boolean callable) {
public final PreparedStatement getBatchStatement(Object key, String sql) {
checkConsistentBatchKey( key );
if ( sql == null ) {
throw new IllegalArgumentException( "sql must be non-null." );
}
PreparedStatement statement = statements.get( sql );
if ( statement == null ) {
statement = buildBatchStatement( sql, callable );
statements.put( sql, statement );
}
else {
log.debug( "reusing batch statement" );
getJdbcServices().getSqlStatementLogger().logStatement( sql );
}
if ( statement != null ) {
log.debug( "reusing prepared statement" );
statementLogger.logStatement( sql );
}
return statement;
}
private PreparedStatement buildBatchStatement(String sql, boolean callable) {
try {
if ( callable ) {
return connectionProxy.prepareCall( sql );
}
else {
return connectionProxy.prepareStatement( sql );
}
/**
* {@inheritDoc}
*/
// TODO: should this be final???
@Override
public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement) {
checkConsistentBatchKey( key );
if ( sql == null ) {
throw new IllegalArgumentException( "sql must be non-null." );
}
catch ( SQLException sqle ) {
log.error( "sqlexception escaped proxy", sqle );
throw getJdbcServices().getSqlExceptionHelper().convert( sqle, "could not prepare batch statement", sql );
if ( statements.put( sql, preparedStatement ) != null ) {
log.error( "PreparedStatement was already in the batch, [" + sql + "]." );
}
}
protected void checkConsistentBatchKey(Object key) {
if ( ! this.key.equals( key ) ) {
throw new IllegalStateException(
"specified key ["+ key + "] is different from internal batch key [" + this.key + "]."
);
}
}
@ -142,7 +162,7 @@ public abstract class AbstractBatchImpl implements Batch {
doExecuteBatch();
}
finally {
releaseStatements();
release();
}
}
finally {

View File

@ -28,6 +28,8 @@ import org.slf4j.LoggerFactory;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
/**
* A builder for {@link Batch} instances.
@ -46,15 +48,17 @@ public class BatchBuilder {
this.size = size;
}
public void setSize(int size) {
public void setJdbcBatchSize(int size) {
this.size = size;
}
public Batch buildBatch(Object key, LogicalConnectionImplementor logicalConnection) {
public Batch buildBatch(Object key,
SQLStatementLogger statementLogger,
SQLExceptionHelper exceptionHelper) {
log.trace( "building batch [size={}]", size );
return size > 1
? new BatchingBatch( key, logicalConnection, size )
: new NonBatchingBatch( key, logicalConnection );
? new BatchingBatch( key, statementLogger, exceptionHelper, size )
: new NonBatchingBatch( key, statementLogger, exceptionHelper );
}
}

View File

@ -25,18 +25,24 @@ package org.hibernate.engine.jdbc.batch.internal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
import org.hibernate.jdbc.Expectation;
/**
* A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does batching based on a given size. Once the batch size is exceeded, the
* batch is implicitly executed.
* A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does
* batching based on a given size. Once the batch size is reached for a statement
* in the batch, the entire batch is implicitly executed.
*
* @author Steve Ebersole
*/
@ -44,33 +50,54 @@ public class BatchingBatch extends AbstractBatchImpl {
private static final Logger log = LoggerFactory.getLogger( BatchingBatch.class );
private final int batchSize;
private Expectation[] expectations;
private int batchPosition;
public BatchingBatch(Object key, LogicalConnectionImplementor logicalConnection, int batchSize) {
super( key, logicalConnection );
// TODO: A Map is used for expectations so it is possible to track when a batch
// is full (i.e., when the batch for a particular statement exceeds batchSize)
// Until HHH-5797 is fixed, there will only be 1 statement in a batch, so it won't
// be necessary to track expectations by statement.
private Map<String, List<Expectation>> expectationsBySql;
private int maxBatchPosition;
public BatchingBatch(Object key,
SQLStatementLogger statementLogger,
SQLExceptionHelper exceptionHelper,
int batchSize) {
super( key, statementLogger, exceptionHelper );
this.batchSize = batchSize;
this.expectations = new Expectation[ batchSize ];
this.expectationsBySql = new HashMap<String, List<Expectation>>();
}
/**
* {@inheritDoc}
*/
public void addToBatch(Expectation expectation) {
if ( !expectation.canBeBatched() ) {
public void addToBatch(Object key, String sql, Expectation expectation) {
checkConsistentBatchKey( key );
if ( sql == null || expectation == null ) {
throw new AssertionFailure( "sql or expection was null." );
}
if ( ! expectation.canBeBatched() ) {
throw new HibernateException( "attempting to batch an operation which cannot be batched" );
}
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
try {
entry.getValue().addBatch();
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getJdbcServices().getSqlExceptionHelper().convert( e, "could not perform addBatch", entry.getKey() );
}
final PreparedStatement statement = getStatements().get( sql );
try {
statement.addBatch();
}
expectations[ batchPosition++ ] = expectation;
if ( batchPosition == batchSize ) {
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getSqlExceptionHelper().convert( e, "could not perform addBatch", sql );
}
List<Expectation> expectations = expectationsBySql.get( sql );
if ( expectations == null ) {
expectations = new ArrayList<Expectation>( batchSize );
expectationsBySql.put( sql, expectations );
}
expectations.add( expectation );
maxBatchPosition = Math.max( maxBatchPosition, expectations.size() );
// TODO: When HHH-5797 is fixed the following if-block should probably be moved before
// adding the batch to the current statement (to detect that we have finished
// with the previous entity).
if ( maxBatchPosition == batchSize ) {
notifyObserversImplicitExecution();
doExecuteBatch();
}
@ -80,46 +107,89 @@ public class BatchingBatch extends AbstractBatchImpl {
* {@inheritDoc}
*/
protected void doExecuteBatch() {
if ( batchPosition == 0 ) {
if ( maxBatchPosition == 0 ) {
log.debug( "no batched statements to execute" );
}
else {
if ( log.isDebugEnabled() ) {
log.debug( "Executing batch size: " + batchPosition );
log.debug( "Executing {} statements with maximum batch size {} ",
getStatements().size(), maxBatchPosition
);
}
try {
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
try {
final PreparedStatement statement = entry.getValue();
checkRowCounts( statement.executeBatch(), statement );
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getJdbcServices().getSqlExceptionHelper()
.convert( e, "could not perform addBatch", entry.getKey() );
}
}
executeStatements();
}
catch ( RuntimeException re ) {
log.error( "Exception executing batch [{}]", re.getMessage() );
throw re;
}
finally {
batchPosition = 0;
for ( List<Expectation> expectations : expectationsBySql.values() ) {
expectations.clear();
}
maxBatchPosition = 0;
}
}
}
private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException {
private void executeStatements() {
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
final String sql = entry.getKey();
final PreparedStatement statement = entry.getValue();
final List<Expectation> expectations = expectationsBySql.get( sql );
if ( batchSize < expectations.size() ) {
throw new IllegalStateException(
"Number of expectations [" + expectations.size() +
"] is greater than batch size [" + batchSize +
"] for statement [" + sql +
"]"
);
}
if ( expectations.size() > 0 ) {
if ( log.isDebugEnabled() ) {
log.debug( "Executing with batch of size {}: {}", expectations.size(), sql );
}
executeStatement( sql, statement, expectations );
expectations.clear();
}
else {
if ( log.isDebugEnabled() ) {
log.debug( "Skipped executing because batch size is 0: ", sql );
}
}
}
}
private void executeStatement(String sql, PreparedStatement ps, List<Expectation> expectations) {
try {
checkRowCounts( sql, ps.executeBatch(), ps, expectations );
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getSqlExceptionHelper()
.convert( e, "could not execute statement: " + sql );
}
}
private void checkRowCounts(String sql, int[] rowCounts, PreparedStatement ps, List<Expectation> expectations) {
int numberOfRowCounts = rowCounts.length;
if ( numberOfRowCounts != batchPosition ) {
if ( numberOfRowCounts != expectations.size() ) {
log.warn( "JDBC driver did not return the expected number of row counts" );
}
for ( int i = 0; i < numberOfRowCounts; i++ ) {
expectations[i].verifyOutcome( rowCounts[i], ps, i );
try {
for ( int i = 0; i < numberOfRowCounts; i++ ) {
expectations.get( i ).verifyOutcome( rowCounts[i], ps, i );
}
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getSqlExceptionHelper()
.convert( e, "row count verification failed for statement: ", sql );
}
}
public void release() {
expectationsBySql.clear();
maxBatchPosition = 0;
}
}

View File

@ -25,12 +25,12 @@ package org.hibernate.engine.jdbc.batch.internal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
import org.hibernate.jdbc.Expectation;
/**
@ -42,22 +42,26 @@ import org.hibernate.jdbc.Expectation;
public class NonBatchingBatch extends AbstractBatchImpl {
private static final Logger log = LoggerFactory.getLogger( NonBatchingBatch.class );
protected NonBatchingBatch(Object key, LogicalConnectionImplementor logicalConnection) {
super( key, logicalConnection );
protected NonBatchingBatch(Object key,
SQLStatementLogger statementLogger,
SQLExceptionHelper exceptionHelper) {
super( key, statementLogger, exceptionHelper );
}
public void addToBatch(Expectation expectation) {
public void addToBatch(Object key, String sql, Expectation expectation) {
checkConsistentBatchKey( key );
if ( sql == null ) {
throw new IllegalArgumentException( "sql must be non-null." );
}
notifyObserversImplicitExecution();
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
try {
final PreparedStatement statement = entry.getValue();
final int rowCount = statement.executeUpdate();
expectation.verifyOutcome( rowCount, statement, 0 );
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getJdbcServices().getSqlExceptionHelper().convert( e, "could not execute batch statement", entry.getKey() );
}
try {
final PreparedStatement statement = getStatements().get( sql );
final int rowCount = statement.executeUpdate();
expectation.verifyOutcome( rowCount, statement, 0 );
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getSqlExceptionHelper().convert( e, "could not execute batch statement", sql );
}
}

View File

@ -52,20 +52,30 @@ public interface Batch {
public void addObserver(BatchObserver observer);
/**
* Get a statement which is part of the batch, creating if necessary (and storing for next time).
* Get a statement which is part of the batch.
*
* @param sql The SQL statement.
* @param callable Is the SQL statement callable?
* @return The prepared statement instance, representing the SQL statement.
* @return the prepared statement representing the SQL statement, if the batch contained it;
* null, otherwise.
*/
public PreparedStatement getBatchStatement(String sql, boolean callable);
public PreparedStatement getBatchStatement(Object key, String sql);
/**
* Add a prepared statement to the batch.
*
* @param sql The SQL statement.
*/
public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement);
/**
* Indicates completion of the current part of the batch.
*
* @param key
* @param sql
* @param expectation The expectation for the part's result.
*/
public void addToBatch(Expectation expectation);
public void addToBatch(Object key, String sql, Expectation expectation);
/**
* Execute this batch.

View File

@ -30,7 +30,6 @@ import java.io.ObjectOutputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.slf4j.Logger;
@ -41,12 +40,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.batch.internal.BatchBuilder;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.spi.ConnectionManager;
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
import org.hibernate.jdbc.Batcher;
import org.hibernate.jdbc.Expectation;
/**
@ -67,15 +65,13 @@ public class ConnectionManagerImpl implements ConnectionManager {
// TODO: check if it's ok to change the method names in Callback
private transient SessionFactoryImplementor factory;
private transient Connection proxiedConnection;
private transient Interceptor interceptor;
private final Callback callback;
private long transactionTimeout = -1;
boolean isTransactionTimeoutSet;
private transient LogicalConnectionImpl logicalConnection;
private transient StatementPreparer statementPreparer;
private final transient BatchBuilder batchBuilder;
private Batch batch;
/**
* Constructs a ConnectionManager.
@ -99,8 +95,7 @@ public class ConnectionManagerImpl implements ConnectionManager {
suppliedConnection,
releaseMode,
factory.getJdbcServices(),
factory.getStatistics() != null ? factory.getStatisticsImplementor() : null,
factory.getSettings().getBatcherFactory()
factory.getStatistics() != null ? factory.getStatisticsImplementor() : null
)
);
}
@ -114,16 +109,12 @@ public class ConnectionManagerImpl implements ConnectionManager {
Interceptor interceptor,
LogicalConnectionImpl logicalConnection
) {
this.factory = factory;
this.callback = callback;
this.interceptor = interceptor;
setupConnection( logicalConnection );
}
private void setupConnection(LogicalConnectionImpl logicalConnection) {
this.logicalConnection = logicalConnection;
this.logicalConnection.addObserver( callback );
proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
this.statementPreparer = new StatementPreparer( logicalConnection, factory.getSettings() );
this.batchBuilder = factory.getSettings().getBatchBuilder();
}
/**
@ -271,7 +262,9 @@ 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();
if ( statementPreparer != null ) {
statementPreparer.unsetTransactionTimeout();
}
}
private boolean isAfterTransactionRelease() {
@ -282,37 +275,15 @@ public class ConnectionManagerImpl implements ConnectionManager {
return logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.ON_CLOSE;
}
public boolean isLogicallyConnected() {
private boolean isLogicallyConnected() {
return logicalConnection != null && logicalConnection.isOpen();
}
@Override
public void setTransactionTimeout(int seconds) {
isTransactionTimeoutSet = true;
transactionTimeout = System.currentTimeMillis() / 1000 + seconds;
statementPreparer.setTransactionTimeout( 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.
@ -337,6 +308,7 @@ public class ConnectionManagerImpl implements ConnectionManager {
if ( ! isLogicallyConnected() ) {
throw new IllegalStateException( "cannot manually disconnect because not logically connected." );
}
releaseBatch();
return logicalConnection.manualDisconnect();
}
@ -382,10 +354,14 @@ public class ConnectionManagerImpl implements ConnectionManager {
}
try {
log.trace( "performing cleanup" );
releaseBatch();
statementPreparer.close();
Connection c = logicalConnection.close();
return c;
}
finally {
batch = null;
statementPreparer = null;
logicalConnection = null;
}
}
@ -412,105 +388,68 @@ 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)}).
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
@Override
public PreparedStatement prepareStatement(String sql, final int autoGeneratedKeys)
throws HibernateException {
if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) {
checkAutoGeneratedKeysSupportEnabled();
}
StatementPreparer statementPreparer = new StatementPreparer( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return proxiedConnection.prepareStatement( getSqlToPrepare(), autoGeneratedKeys );
}
};
return prepareStatement( statementPreparer, true );
executeBatch();
return statementPreparer.prepareStatement( getSQL( sql ), autoGeneratedKeys );
}
/**
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}).
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
@Override
public PreparedStatement prepareStatement(String sql, final String[] columnNames) {
checkAutoGeneratedKeysSupportEnabled();
StatementPreparer statementPreparer = new StatementPreparer( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return proxiedConnection.prepareStatement( getSqlToPrepare(), columnNames );
}
};
return prepareStatement( statementPreparer, true );
}
private void checkAutoGeneratedKeysSupportEnabled() {
if ( ! factory.getSettings().isGetGeneratedKeysEnabled() ) {
throw new AssertionFailure("getGeneratedKeys() support is not enabled");
}
executeBatch();
return statementPreparer.prepareStatement( getSQL( sql ), columnNames );
}
/**
* Get a non-batchable prepared statement to use for selecting. Does not
* result in execution of the current batch.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
*/
@Override
public PreparedStatement prepareSelectStatement(String sql) {
return prepareStatement( sql, false, false );
return statementPreparer.prepareStatement( getSQL( sql ), false );
}
/**
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
@Override
public PreparedStatement prepareStatement(String sql, final boolean isCallable) {
return prepareStatement( sql, isCallable, true );
executeBatch();
return statementPreparer.prepareStatement( getSQL( sql ), isCallable );
}
/**
* Get a non-batchable callable statement to use for inserting / deleting / updating.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
@Override
public CallableStatement prepareCallableStatement(String sql) {
executeBatch();
log.trace("preparing callable statement");
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
);
return CallableStatement.class.cast( statementPreparer.prepareStatement( getSQL( sql ), true ) );
}
/**
@ -518,105 +457,97 @@ public class ConnectionManagerImpl implements ConnectionManager {
* (might be called many times before a single call to <tt>executeBatch()</tt>).
* After setting parameters, call <tt>addToBatch</tt> - do not execute the
* statement explicitly.
* @see org.hibernate.jdbc.Batcher#addToBatch
* @see org.hibernate.engine.jdbc.batch.spi.Batch#addToBatch
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
public PreparedStatement prepareBatchStatement(String sql, boolean isCallable) {
String batchUpdateSQL = getSQL( sql );
PreparedStatement batchUpdate = getBatcher().getStatement( batchUpdateSQL );
if ( batchUpdate == null ) {
batchUpdate = prepareStatement( batchUpdateSQL, isCallable, true ); // calls executeBatch()
getBatcher().setStatement( batchUpdateSQL, batchUpdate );
@Override
public PreparedStatement prepareBatchStatement(Object key, String sql, boolean isCallable) {
if ( key == null ) {
throw new IllegalArgumentException( "batch key must be non-null." );
}
else {
log.debug( "reusing prepared statement" );
factory.getJdbcServices().getSqlStatementLogger().logStatement( batchUpdateSQL );
String actualSQL = getSQL( sql );
PreparedStatement batchUpdate = null;
if ( batch != null ) {
if ( key.equals( batch.getKey() ) ) {
batchUpdate = batch.getBatchStatement( key, actualSQL );
}
else {
batch.execute();
batch = null;
}
}
if ( batch == null ) {
batch = batchBuilder.buildBatch(
key,
logicalConnection.getJdbcServices().getSqlStatementLogger(),
logicalConnection.getJdbcServices().getSqlExceptionHelper()
);
}
if ( batchUpdate == null ) {
batchUpdate = statementPreparer.prepareStatement( actualSQL, isCallable );
batch.addBatchStatement( key, actualSQL, batchUpdate );
}
return batchUpdate;
}
private Batcher getBatcher() {
return logicalConnection.getBatcher();
}
/**
* Get a prepared statement for use in loading / querying. If not explicitly
* released by <tt>closeQueryStatement()</tt>, it will be released when the
* session is closed or disconnected.
* Get a prepared statement for use in loading / querying. Does not
* result in execution of the current batch.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
*/
@Override
public PreparedStatement prepareQueryStatement(
String sql,
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()
);
}
final boolean isCallable) {
PreparedStatement ps = (
isScrollable ?
statementPreparer.prepareScrollableQueryStatement(
getSQL( sql ), scrollMode, isCallable
) :
statementPreparer.prepareQueryStatement(
getSQL( sql ), isCallable
)
);
logicalConnection.getResourceRegistry().registerLastQuery( ps );
return ps;
}
/**
* Cancel the current query statement
*/
@Override
public void cancelLastQuery() throws HibernateException {
logicalConnection.getResourceRegistry().cancelLastQuery();
}
public void abortBatch(SQLException sqle) {
getBatcher().abortBatch( sqle );
}
public void addToBatch(Expectation expectation ) {
try {
getBatcher().addToBatch( expectation );
}
catch (SQLException sqle) {
throw logicalConnection.getJdbcServices().getSqlExceptionHelper().convert(
sqle, "could not add to batch statement" );
}
@Override
public void addToBatch(Object batchKey, String sql, Expectation expectation) {
batch.addToBatch( batchKey, sql, expectation );
}
@Override
public void executeBatch() throws HibernateException {
getBatcher().executeBatch();
if ( batch != null ) {
batch.execute();
batch.release(); // needed?
}
}
@Override
public void abortBatch() {
releaseBatch();
}
private void releaseBatch() {
if ( batch != null ) {
batch.release();
}
}
private String getSQL(String sql) {
@ -673,8 +604,7 @@ public class ConnectionManagerImpl implements ConnectionManager {
ois,
factory.getJdbcServices(),
factory.getStatistics() != null ? factory.getStatisticsImplementor() : null,
connectionReleaseMode,
factory.getSettings().getBatcherFactory()
connectionReleaseMode
)
);
}

View File

@ -23,14 +23,11 @@
*/
package org.hibernate.engine.jdbc.internal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@ -42,8 +39,6 @@ import org.hibernate.engine.jdbc.spi.JdbcWrapper;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.engine.jdbc.spi.InvalidatableWrapper;
import org.hibernate.jdbc.Batcher;
import org.hibernate.jdbc.BatcherFactory;
/**
* Standard implementation of the {@link org.hibernate.engine.jdbc.spi.JdbcResourceRegistry} contract
@ -56,13 +51,11 @@ public class JdbcResourceRegistryImpl implements JdbcResourceRegistry {
private final HashMap<Statement,Set<ResultSet>> xref = new HashMap<Statement,Set<ResultSet>>();
private final Set<ResultSet> unassociatedResultSets = new HashSet<ResultSet>();
private final SQLExceptionHelper exceptionHelper;
private final Batcher batcher;
private Statement lastQuery;
public JdbcResourceRegistryImpl(SQLExceptionHelper exceptionHelper, BatcherFactory batcherFactory) {
public JdbcResourceRegistryImpl(SQLExceptionHelper exceptionHelper) {
this.exceptionHelper = exceptionHelper;
this.batcher = batcherFactory.createBatcher( exceptionHelper );
}
public void register(Statement statement) {
@ -73,10 +66,6 @@ public class JdbcResourceRegistryImpl implements JdbcResourceRegistry {
xref.put( statement, null );
}
public Batcher getBatcher() {
return batcher;
}
@SuppressWarnings({ "unchecked" })
public void registerLastQuery(Statement statement) {
log.trace( "registering last query statement [{}]", statement );
@ -183,7 +172,6 @@ public class JdbcResourceRegistryImpl implements JdbcResourceRegistry {
}
private void cleanup() {
batcher.closeStatements();
for ( Map.Entry<Statement,Set<ResultSet>> entry : xref.entrySet() ) {
if ( entry.getValue() != null ) {
for ( ResultSet resultSet : entry.getValue() ) {

View File

@ -41,8 +41,6 @@ import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.jdbc.Batcher;
import org.hibernate.jdbc.BatcherFactory;
import org.hibernate.jdbc.BorrowedConnectionProxy;
import org.hibernate.stat.StatisticsImplementor;
@ -60,7 +58,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
private final ConnectionReleaseMode connectionReleaseMode;
private final JdbcServices jdbcServices;
private final StatisticsImplementor statisticsImplementor;
private final JdbcResourceRegistryImpl jdbcResourceRegistry;
private final JdbcResourceRegistry jdbcResourceRegistry;
private final List<ConnectionObserver> observers = new ArrayList<ConnectionObserver>();
private boolean releasesEnabled = true;
@ -72,31 +70,20 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
public LogicalConnectionImpl(Connection userSuppliedConnection,
ConnectionReleaseMode connectionReleaseMode,
JdbcServices jdbcServices,
StatisticsImplementor statisticsImplementor,
BatcherFactory batcherFactory
StatisticsImplementor statisticsImplementor
) {
this.jdbcServices = jdbcServices;
this.statisticsImplementor = statisticsImplementor;
this( connectionReleaseMode,
jdbcServices,
statisticsImplementor,
userSuppliedConnection != null,
false
);
this.physicalConnection = userSuppliedConnection;
this.connectionReleaseMode =
determineConnectionReleaseMode(
jdbcServices, userSuppliedConnection != null, connectionReleaseMode
);
this.jdbcResourceRegistry =
new JdbcResourceRegistryImpl(
getJdbcServices().getSqlExceptionHelper(),
batcherFactory
);
this.isUserSuppliedConnection = ( userSuppliedConnection != null );
this.isClosed = false;
}
// used for deserialization
private LogicalConnectionImpl(ConnectionReleaseMode connectionReleaseMode,
JdbcServices jdbcServices,
StatisticsImplementor statisticsImplementor,
BatcherFactory batcherFactory,
boolean isUserSuppliedConnection,
boolean isClosed) {
this.connectionReleaseMode = determineConnectionReleaseMode(
@ -105,10 +92,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
this.jdbcServices = jdbcServices;
this.statisticsImplementor = statisticsImplementor;
this.jdbcResourceRegistry =
new JdbcResourceRegistryImpl(
getJdbcServices().getSqlExceptionHelper(),
batcherFactory
);
new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() );
this.isUserSuppliedConnection = isUserSuppliedConnection;
this.isClosed = isClosed;
@ -230,10 +214,6 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
return connectionReleaseMode;
}
public Batcher getBatcher() {
return jdbcResourceRegistry.getBatcher();
}
public boolean hasBorrowedConnection() {
return borrowedConnection != null;
}
@ -436,14 +416,12 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
public static LogicalConnectionImpl deserialize(ObjectInputStream ois,
JdbcServices jdbcServices,
StatisticsImplementor statisticsImplementor,
ConnectionReleaseMode connectionReleaseMode,
BatcherFactory batcherFactory
ConnectionReleaseMode connectionReleaseMode
) throws IOException {
return new LogicalConnectionImpl(
connectionReleaseMode,
jdbcServices,
statisticsImplementor,
batcherFactory,
ois.readBoolean(),
ois.readBoolean()
);

View File

@ -0,0 +1,276 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.internal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.ScrollMode;
import org.hibernate.TransactionException;
import org.hibernate.cfg.Settings;
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
/**
* Prepares statements.
*
* @author Gail Badner
*/
public class StatementPreparer {
private static final Logger log = LoggerFactory.getLogger( StatementPreparer.class );
// TODO: Move JDBC settings into a different object...
private final Settings settings;
private final Connection proxiedConnection;
private final SQLExceptionHelper sqlExceptionHelper;
private long transactionTimeout = -1;
boolean isTransactionTimeoutSet;
/**
* Constructs a StatementPreparer object
* @param logicalConnection - the logical connection
* @param settings - contains settings configured for preparing statements
*/
public StatementPreparer(LogicalConnectionImplementor logicalConnection, Settings settings) {
this.settings = settings;
proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
sqlExceptionHelper = logicalConnection.getJdbcServices().getSqlExceptionHelper();
}
private abstract class StatementPreparation {
private final String sql;
protected abstract PreparedStatement doPrepare() throws SQLException;
public StatementPreparation(String sql) {
this.sql = sql;
}
public String getSql() {
return sql;
}
public void postProcess(PreparedStatement preparedStatement) throws SQLException {
setStatementTimeout( preparedStatement );
}
public PreparedStatement prepareAndPostProcess() {
try {
PreparedStatement ps = doPrepare();
postProcess( ps );
return ps;
}
catch ( SQLException sqle ) {
log.error( "sqlexception escaped proxy", sqle );
throw sqlExceptionHelper.convert(
sqle, "could not prepare statement", sql
);
}
}
}
private abstract class QueryStatementPreparation extends StatementPreparation {
QueryStatementPreparation(String sql) {
super( sql );
}
public void postProcess(PreparedStatement preparedStatement) throws SQLException {
super.postProcess( preparedStatement );
setStatementFetchSize( preparedStatement );
}
}
public void close() {
try {
proxiedConnection.close();
}
catch (SQLException sqle) {
log.error( "sqlexception escaped proxy", sqle );
throw sqlExceptionHelper.convert( sqle, "could not close connection proxy" );
}
}
/**
* Prepare a statement. If configured, the query timeout is set.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
*
* @param sql - the SQL for the statement to be prepared
* @param isCallable - true, if a callable statement is to be prepared
* @return the prepared statement
*/
public PreparedStatement prepareStatement(String sql, final boolean isCallable) {
StatementPreparation statementPreparation = new StatementPreparation( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return isCallable ?
proxiedConnection.prepareCall( getSql() ) :
proxiedConnection.prepareStatement( getSql() );
}
};
return statementPreparation.prepareAndPostProcess();
}
/**
* Get a prepared statement to use for inserting / deleting / updating,
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}).
* If configured, the query timeout is set.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
* @param sql - the SQL for the statement to be prepared
* @param autoGeneratedKeys - a flag indicating whether auto-generated
* keys should be returned; one of
* <code>PreparedStatement.RETURN_GENERATED_KEYS</code> or
* <code>Statement.NO_GENERATED_KEYS</code>
* @return the prepared statement
*/
public PreparedStatement prepareStatement(String sql, final int autoGeneratedKeys)
throws HibernateException {
if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) {
checkAutoGeneratedKeysSupportEnabled();
}
StatementPreparation statementPreparation = new StatementPreparation( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return proxiedConnection.prepareStatement( getSql(), autoGeneratedKeys );
}
};
return statementPreparation.prepareAndPostProcess();
}
/**
* Get a prepared statement to use for inserting / deleting / updating.
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}).
* If configured, the query timeout is set.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
*/
public PreparedStatement prepareStatement(String sql, final String[] columnNames) {
checkAutoGeneratedKeysSupportEnabled();
StatementPreparation preparation = new StatementPreparation( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return proxiedConnection.prepareStatement( getSql(), columnNames );
}
};
return preparation.prepareAndPostProcess();
}
private void checkAutoGeneratedKeysSupportEnabled() {
if ( ! settings.isGetGeneratedKeysEnabled() ) {
throw new AssertionFailure("getGeneratedKeys() support is not enabled");
}
}
/**
* Get a prepared statement for use in loading / querying.
* If configured, the query timeout and statement fetch size are set.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
*/
public PreparedStatement prepareQueryStatement(
String sql,
final boolean isCallable
) {
StatementPreparation prep = new QueryStatementPreparation( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return isCallable ?
proxiedConnection.prepareCall( getSql() ) :
proxiedConnection.prepareStatement( getSql() );
}
};
return prep.prepareAndPostProcess();
}
/**
* Get a scrollable prepared statement for use in loading / querying.
* If configured, the query timeout and statement fetch size are set.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
*/
public PreparedStatement prepareScrollableQueryStatement(
String sql,
final ScrollMode scrollMode,
final boolean isCallable
) {
if ( ! settings.isScrollableResultSetsEnabled() ) {
throw new AssertionFailure("scrollable result sets are not enabled");
}
StatementPreparation prep = new QueryStatementPreparation( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return isCallable ?
proxiedConnection.prepareCall(
getSql(), scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY
) :
proxiedConnection.prepareStatement(
getSql(), scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY
);
}
};
return prep.prepareAndPostProcess();
}
/**
* Sets the transaction timeout.
* @param seconds - number of seconds until the the transaction times out.
*/
public void setTransactionTimeout(int seconds) {
isTransactionTimeoutSet = true;
transactionTimeout = System.currentTimeMillis() / 1000 + seconds;
}
/**
* Unset the transaction timeout, called after the end of a
* transaction.
*/
public 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);
}
}
}
private void setStatementFetchSize(PreparedStatement statement) throws SQLException {
if ( settings.getJdbcFetchSize() != null ) {
statement.setFetchSize( settings.getJdbcFetchSize() );
}
}
}

View File

@ -26,6 +26,10 @@ package org.hibernate.engine.jdbc.internal.proxy;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Invocation handler for {@link java.sql.PreparedStatement} proxies
@ -33,6 +37,8 @@ import java.sql.Statement;
* @author Steve Ebersole
*/
public class PreparedStatementProxyHandler extends AbstractStatementProxyHandler {
private static final Logger log = LoggerFactory.getLogger( ConnectionProxyHandler.class );
private final String sql;
protected PreparedStatementProxyHandler(
@ -63,6 +69,7 @@ public class PreparedStatementProxyHandler extends AbstractStatementProxyHandler
}
private void journalParameterBind(Method method, Object[] args) {
log.trace( "binding via {}: []", method.getName(), Arrays.asList( args ) );
}
private boolean isExecution(Method method) {

View File

@ -79,6 +79,10 @@ public interface ConnectionManager extends Serializable {
*/
void afterStatement();
/**
* Sets the transaction timeout.
* @param seconds - number of seconds until the the transaction times out.
*/
void setTransactionTimeout(int seconds);
/**
@ -131,28 +135,43 @@ 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)}).
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
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[])}).
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
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.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
*/
public PreparedStatement prepareSelectStatement(String sql);
/**
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
public PreparedStatement prepareStatement(String sql, boolean isCallable);
/**
* Get a non-batchable callable statement to use for inserting / deleting / updating.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
public CallableStatement prepareCallableStatement(String sql);
@ -161,28 +180,34 @@ public interface ConnectionManager extends Serializable {
* (might be called many times before a single call to <tt>executeBatch()</tt>).
* After setting parameters, call <tt>addToBatch</tt> - do not execute the
* statement explicitly.
* @see org.hibernate.jdbc.Batcher#addToBatch
* @see org.hibernate.engine.jdbc.batch.spi.Batch#addToBatch
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
* released when the session is closed or disconnected.
*/
public PreparedStatement prepareBatchStatement(String sql, boolean isCallable);
public PreparedStatement prepareBatchStatement(Object key, String sql, boolean isCallable);
/**
* Get a prepared statement for use in loading / querying. If not explicitly
* released by <tt>closeQueryStatement()</tt>, it will be released when the
* session is closed or disconnected.
* Get a prepared statement for use in loading / querying. Does not
* result in execution of the current batch.
* <p/>
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
* it will be released when the session is closed or disconnected.
*/
public PreparedStatement prepareQueryStatement(
String sql,
boolean isScrollable,
ScrollMode scrollMode,
boolean isCallable);
/**
* Cancel the current query statement
*/
public void cancelLastQuery();
public void abortBatch(SQLException sqle);
public void abortBatch();
public void addToBatch(Expectation expectation );
public void addToBatch(Object batchKey, String sql, Expectation expectation);
public void executeBatch();
}

View File

@ -99,7 +99,6 @@ import org.hibernate.event.EventListeners;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.jdbc.BatcherFactory;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
@ -1235,10 +1234,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
return filters.keySet();
}
public BatcherFactory getBatcherFactory() {
return settings.getBatcherFactory();
}
public IdentifierGenerator getIdentifierGenerator(String rootEntityName) {
return (IdentifierGenerator) identifierGenerators.get(rootEntityName);
}

View File

@ -1,161 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.jdbc;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
/**
* Manages prepared statements and batching.
*
* @author Gavin King
*/
public abstract class AbstractBatcher implements Batcher {
protected static final Logger log = LoggerFactory.getLogger( AbstractBatcher.class );
private final SQLExceptionHelper exceptionHelper;
private final int jdbcBatchSize;
private PreparedStatement batchUpdate;
private String batchUpdateSQL;
private boolean isClosingBatchUpdate = false;
public AbstractBatcher(SQLExceptionHelper exceptionHelper, int jdbcBatchSize) {
this.exceptionHelper = exceptionHelper;
this.jdbcBatchSize = jdbcBatchSize;
}
public final int getJdbcBatchSize() {
return jdbcBatchSize;
}
public boolean hasOpenResources() {
try {
return !isClosingBatchUpdate && batchUpdate != null && ! batchUpdate.isClosed();
}
catch (SQLException sqle) {
throw exceptionHelper.convert(
sqle,
"Could check to see if batch statement was closed",
batchUpdateSQL
);
}
}
public PreparedStatement getStatement(String sql) {
return batchUpdate != null && batchUpdateSQL.equals( sql ) ? batchUpdate : null;
}
public void setStatement(String sql, PreparedStatement ps) {
checkNotClosingBatchUpdate();
batchUpdateSQL = sql;
batchUpdate = ps;
}
protected PreparedStatement getStatement() {
return batchUpdate;
}
public void abortBatch(SQLException sqle) {
closeStatements();
}
/**
* Actually releases the batcher, allowing it to cleanup internally held
* resources.
*/
public void closeStatements() {
try {
closeBatchUpdate();
}
catch ( SQLException sqle ) {
//no big deal
log.warn( "Could not close a JDBC prepared statement", sqle );
}
batchUpdate = null;
batchUpdateSQL = null;
}
public void executeBatch() throws HibernateException {
checkNotClosingBatchUpdate();
if (batchUpdate!=null) {
try {
try {
doExecuteBatch(batchUpdate);
}
finally {
closeBatchUpdate();
}
}
catch (SQLException sqle) {
throw exceptionHelper.convert(
sqle,
"Could not execute JDBC batch update",
batchUpdateSQL
);
}
finally {
batchUpdate=null;
batchUpdateSQL=null;
}
}
}
protected abstract void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException;
private void closeBatchUpdate() throws SQLException{
checkNotClosingBatchUpdate();
try {
if ( batchUpdate != null ) {
isClosingBatchUpdate = true;
batchUpdate.close();
}
}
finally {
isClosingBatchUpdate = false;
}
}
private void checkNotClosingBatchUpdate() {
if ( isClosingBatchUpdate ) {
throw new IllegalStateException( "Cannot perform operation while closing batch update." );
}
}
}

View File

@ -1,76 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.jdbc;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.ScrollMode;
import org.hibernate.dialect.Dialect;
/**
* Manages <tt>PreparedStatement</tt>s for a session. Abstracts JDBC
* batching to maintain the illusion that a single logical batch
* exists for the whole session, even when batching is disabled.
* Provides transparent <tt>PreparedStatement</tt> caching.
*
* @see java.sql.PreparedStatement
* @see org.hibernate.impl.SessionImpl
* @author Gavin King
*/
public interface Batcher {
public PreparedStatement getStatement(String sql);
public void setStatement(String sql, PreparedStatement ps);
public boolean hasOpenResources();
/**
* Add an insert / delete / update to the current batch (might be called multiple times
* for single <tt>prepareBatchStatement()</tt>)
*/
public void addToBatch(Expectation expectation) throws SQLException, HibernateException;
/**
* Execute the batch
*/
public void executeBatch() throws HibernateException;
/**
* Must be called when an exception occurs
* @param sqle the (not null) exception that is the reason for aborting
*/
public void abortBatch(SQLException sqle);
/**
* Actually releases the batcher, allowing it to cleanup internally held
* resources.
*/
public void closeStatements();
}

View File

@ -1,38 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.jdbc;
import org.hibernate.Interceptor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
/**
* Factory for <tt>Batcher</tt> instances.
* @author Gavin King
*/
public interface BatcherFactory {
public void setJdbcBatchSize(int jdbcBatchSize);
public Batcher createBatcher(SQLExceptionHelper exceptionHelper);
}

View File

@ -1,100 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.jdbc;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
/**
* An implementation of the <tt>Batcher</tt> interface that
* actually uses batching
* @author Gavin King
*/
public class BatchingBatcher extends AbstractBatcher {
private Expectation[] expectations;
private int currentSize;
public BatchingBatcher(SQLExceptionHelper exceptionHelper, int jdbcBatchSize) {
super( exceptionHelper, jdbcBatchSize );
expectations = new Expectation[ jdbcBatchSize ];
currentSize = 0;
}
public void addToBatch(Expectation expectation) throws SQLException, HibernateException {
if ( !expectation.canBeBatched() ) {
throw new HibernateException( "attempting to batch an operation which cannot be batched" );
}
PreparedStatement batchUpdate = getStatement();
batchUpdate.addBatch();
expectations[ currentSize++ ] = expectation;
if ( currentSize == getJdbcBatchSize() ) {
doExecuteBatch( batchUpdate );
}
}
protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
if ( currentSize == 0 ) {
log.debug( "no batched statements to execute" );
}
else {
if ( log.isDebugEnabled() ) {
log.debug( "Executing batch size: " + currentSize );
}
try {
checkRowCounts( ps.executeBatch(), ps );
}
catch (RuntimeException re) {
log.error( "Exception executing batch: ", re );
throw re;
}
finally {
currentSize = 0;
}
}
}
private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException {
int numberOfRowCounts = rowCounts.length;
if ( numberOfRowCounts != currentSize ) {
log.warn( "JDBC driver did not return the expected number of row counts" );
}
for ( int i = 0; i < numberOfRowCounts; i++ ) {
expectations[i].verifyOutcome( rowCounts[i], ps, i );
}
}
}

View File

@ -1,48 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.jdbc;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
/**
* A BatcherFactory implementation which constructs Batcher instances
* capable of actually performing batch operations.
*
* @author Gavin King
*/
public class BatchingBatcherFactory implements BatcherFactory {
private int jdbcBatchSize;
public void setJdbcBatchSize(int jdbcBatchSize) {
this.jdbcBatchSize = jdbcBatchSize;
}
public Batcher createBatcher(SQLExceptionHelper exceptionHelper) {
return new BatchingBatcher( exceptionHelper, jdbcBatchSize );
}
}

View File

@ -1,53 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.jdbc;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
/**
* An implementation of the <tt>Batcher</tt> interface that does no batching
*
* @author Gavin King
*/
public class NonBatchingBatcher extends AbstractBatcher {
public NonBatchingBatcher(SQLExceptionHelper exceptionHelper) {
super( exceptionHelper, 1 );
}
public void addToBatch(Expectation expectation) throws SQLException, HibernateException {
PreparedStatement statement = getStatement();
final int rowCount = statement.executeUpdate();
expectation.verifyOutcome( rowCount, statement, 0 );
}
protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
}
}

View File

@ -1,49 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.jdbc;
import org.hibernate.AssertionFailure;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
/**
* A BatcherFactory implementation which constructs Batcher instances
* that do not perform batch operations.
*
* @author Gavin King
*/
public class NonBatchingBatcherFactory implements BatcherFactory {
public void setJdbcBatchSize(int jdbcBatchSize) {
if ( jdbcBatchSize > 1 ) {
throw new AssertionFailure( "jdbcBatchSize must be 1 for " + getClass().getName() );
}
}
public Batcher createBatcher(SQLExceptionHelper exceptionHelper) {
return new NonBatchingBatcher( exceptionHelper );
}
}

View File

@ -1083,7 +1083,7 @@ public abstract class AbstractCollectionPersister
boolean useBatch = expectation.canBeBatched();
String sql = getSQLDeleteString();
if ( useBatch ) {
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, callable );
}
else {
st = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable );
@ -1095,7 +1095,7 @@ public abstract class AbstractCollectionPersister
writeKey( st, id, offset, session );
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
expectation.verifyOutcome( st.executeUpdate(), st, -1 );
@ -1103,7 +1103,7 @@ public abstract class AbstractCollectionPersister
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}
@ -1161,7 +1161,9 @@ public abstract class AbstractCollectionPersister
String sql = getSQLInsertRowString();
if ( useBatch ) {
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement(
this, sql, callable
);
}
else {
st = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable );
@ -1182,7 +1184,7 @@ public abstract class AbstractCollectionPersister
loc = writeElement(st, collection.getElement(entry), loc, session );
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
expectation.verifyOutcome( st.executeUpdate(), st, -1 );
@ -1193,7 +1195,7 @@ public abstract class AbstractCollectionPersister
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}
@ -1261,7 +1263,9 @@ public abstract class AbstractCollectionPersister
String sql = getSQLDeleteRowString();
if ( useBatch ) {
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement(
this, sql, callable
);
}
else {
st = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable );
@ -1286,7 +1290,7 @@ public abstract class AbstractCollectionPersister
}
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
expectation.verifyOutcome( st.executeUpdate(), st, -1 );
@ -1295,7 +1299,7 @@ public abstract class AbstractCollectionPersister
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}
@ -1361,7 +1365,9 @@ public abstract class AbstractCollectionPersister
if ( useBatch ) {
if ( st == null ) {
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement(
this, sql, callable
);
}
}
else {
@ -1381,7 +1387,7 @@ public abstract class AbstractCollectionPersister
writeElement(st, collection.getElement(entry), offset, session );
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
expectation.verifyOutcome( st.executeUpdate(), st, -1 );
@ -1391,7 +1397,7 @@ public abstract class AbstractCollectionPersister
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}

View File

@ -211,7 +211,9 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
if ( useBatch ) {
if ( st == null ) {
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement(
this, sql, callable
);
}
}
else {
@ -235,7 +237,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
}
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
expectation.verifyOutcome( st.executeUpdate(), st, -1 );
@ -243,7 +245,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}

View File

@ -196,27 +196,26 @@ public class OneToManyPersister extends AbstractCollectionPersister {
Object entry = entries.next();
if ( collection.needsUpdating( entry, i, elementType ) ) { // will still be issued when it used to be null
String sql = getSQLDeleteRowString();
if ( st == null ) {
String sql = getSQLDeleteRowString();
if ( isDeleteCallable() ) {
expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() );
useBatch = expectation.canBeBatched();
st = useBatch
? session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, true )
? session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, true )
: session.getJDBCContext().getConnectionManager().prepareStatement( sql, true );
offset += expectation.prepare( st );
}
else {
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement(
getSQLDeleteRowString(),
false
this, sql, false
);
}
}
int loc = writeKey( st, id, offset, session );
writeElementToWhere( st, collection.getSnapshotElement(entry, i), loc, session );
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
expectation.verifyOutcome( st.executeUpdate(), st, -1 );
@ -228,7 +227,7 @@ public class OneToManyPersister extends AbstractCollectionPersister {
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}
@ -255,7 +254,9 @@ public class OneToManyPersister extends AbstractCollectionPersister {
if ( collection.needsUpdating( entry, i, elementType ) ) {
if ( useBatch ) {
if ( st == null ) {
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
st = session.getJDBCContext().getConnectionManager().prepareBatchStatement(
this, sql, callable
);
}
}
else {
@ -272,7 +273,7 @@ public class OneToManyPersister extends AbstractCollectionPersister {
writeElementToWhere( st, collection.getElement( entry ), loc, session );
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
expectation.verifyOutcome( st.executeUpdate(), st, -1 );
@ -284,7 +285,7 @@ public class OneToManyPersister extends AbstractCollectionPersister {
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}

View File

@ -2381,7 +2381,7 @@ public abstract class AbstractEntityPersister
// Render the SQL query
final PreparedStatement insert;
if ( useBatch ) {
insert = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
insert = session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, callable );
}
else {
insert = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable );
@ -2398,7 +2398,7 @@ public abstract class AbstractEntityPersister
if ( useBatch ) {
// TODO : shouldnt inserts be Expectations.NONE?
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
expectation.verifyOutcome( insert.executeUpdate(), insert, -1 );
@ -2407,7 +2407,7 @@ public abstract class AbstractEntityPersister
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}
@ -2500,7 +2500,7 @@ public abstract class AbstractEntityPersister
int index = 1; // starting index
final PreparedStatement update;
if ( useBatch ) {
update = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
update = session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, callable );
}
else {
update = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable );
@ -2543,7 +2543,7 @@ public abstract class AbstractEntityPersister
}
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
return true;
}
else {
@ -2553,7 +2553,7 @@ public abstract class AbstractEntityPersister
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}
@ -2614,7 +2614,7 @@ public abstract class AbstractEntityPersister
PreparedStatement delete;
int index = 1;
if ( useBatch ) {
delete = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable );
delete = session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, callable );
}
else {
delete = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable );
@ -2649,7 +2649,7 @@ public abstract class AbstractEntityPersister
}
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().addToBatch( expectation );
session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation );
}
else {
check( delete.executeUpdate(), id, j, expectation, delete );
@ -2658,7 +2658,7 @@ public abstract class AbstractEntityPersister
}
catch ( SQLException sqle ) {
if ( useBatch ) {
session.getJDBCContext().getConnectionManager().abortBatch( sqle );
session.getJDBCContext().getConnectionManager().abortBatch();
}
throw sqle;
}

View File

@ -10,6 +10,7 @@ import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.testing.junit.functional.FunctionalTestCase;
import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.cfg.Configuration;
@ -49,16 +50,37 @@ public class BatchTest extends FunctionalTestCase {
final int N = 5000; //26 secs with batch flush, 26 without
//final int N = 100000; //53 secs with batch flush, OOME without
//final int N = 250000; //137 secs with batch flush, OOME without
int batchSize = ( ( SessionFactoryImplementor ) getSessions() ).getSettings().getJdbcBatchSize();
doBatchInsertUpdate( N, batchSize );
System.out.println( System.currentTimeMillis() - start );
}
public void testBatchInsertUpdateSizeEqJdbcBatchSize() {
int batchSize = ( ( SessionFactoryImplementor ) getSessions() ).getSettings().getJdbcBatchSize();
doBatchInsertUpdate( 50, batchSize );
}
public void testBatchInsertUpdateSizeLtJdbcBatchSize() {
int batchSize = ( ( SessionFactoryImplementor ) getSessions() ).getSettings().getJdbcBatchSize();
doBatchInsertUpdate( 50, batchSize - 1 );
}
public void testBatchInsertUpdateSizeGtJdbcBatchSize() {
long start = System.currentTimeMillis();
int batchSize = ( ( SessionFactoryImplementor ) getSessions() ).getSettings().getJdbcBatchSize();
doBatchInsertUpdate( 50, batchSize + 1 );
}
public void doBatchInsertUpdate(int nEntities, int nBeforeFlush) {
Session s = openSession();
s.setCacheMode( CacheMode.IGNORE );
Transaction t = s.beginTransaction();
for ( int i = 0; i < N; i++ ) {
for ( int i = 0; i < nEntities; i++ ) {
DataPoint dp = new DataPoint();
dp.setX( new BigDecimal( i * 0.1d ).setScale( 19, BigDecimal.ROUND_DOWN ) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale( 19, BigDecimal.ROUND_DOWN ) );
s.save( dp );
if ( i % 20 == 0 ) {
if ( i + 1 % nBeforeFlush == 0 ) {
s.flush();
s.clear();
}
@ -75,15 +97,30 @@ public class BatchTest extends FunctionalTestCase {
while ( sr.next() ) {
DataPoint dp = ( DataPoint ) sr.get( 0 );
dp.setDescription( "done!" );
if ( ++i % 20 == 0 ) {
if ( ++i % nBeforeFlush == 0 ) {
s.flush();
s.clear();
}
}
t.commit();
s.close();
System.out.println( System.currentTimeMillis() - start );
}
s = openSession();
s.setCacheMode( CacheMode.IGNORE );
t = s.beginTransaction();
i = 0;
sr = s.createQuery( "from DataPoint dp order by dp.x asc" )
.scroll( ScrollMode.FORWARD_ONLY );
while ( sr.next() ) {
DataPoint dp = ( DataPoint ) sr.get( 0 );
s.delete( dp );
if ( ++i % nBeforeFlush == 0 ) {
s.flush();
s.clear();
}
}
t.commit();
s.close();
}
}

View File

@ -3,22 +3,21 @@ package org.hibernate.test.insertordering;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import junit.framework.Test;
import org.hibernate.engine.jdbc.batch.internal.BatchBuilder;
import org.hibernate.engine.jdbc.batch.internal.BatchingBatch;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
import org.hibernate.testing.junit.functional.FunctionalTestCase;
import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.Session;
import org.hibernate.HibernateException;
import org.hibernate.jdbc.BatchingBatcher;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.BatcherFactory;
import org.hibernate.jdbc.Batcher;
/**
* {@inheritDoc}
@ -42,7 +41,7 @@ public class InsertOrderingTest extends FunctionalTestCase {
super.configure( cfg );
cfg.setProperty( Environment.ORDER_INSERTS, "true" );
cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "10" );
cfg.setProperty( Environment.BATCH_STRATEGY, StatsBatcherFactory.class.getName() );
cfg.setProperty( Environment.BATCH_STRATEGY, StatsBatchBuilder.class.getName() );
}
public void testBatchOrdering() {
@ -56,11 +55,11 @@ public class InsertOrderingTest extends FunctionalTestCase {
s.save( group );
user.addMembership( group );
}
StatsBatcher.reset();
StatsBatch.reset();
s.getTransaction().commit();
s.close();
assertEquals( 3, StatsBatcher.batchSizes.size() );
assertEquals( 3, StatsBatch.batchSizes.size() );
s = openSession();
s.beginTransaction();
@ -76,13 +75,13 @@ public class InsertOrderingTest extends FunctionalTestCase {
public int count = 0;
}
public static class StatsBatcher extends BatchingBatcher {
public static class StatsBatch extends BatchingBatch {
private static String batchSQL;
private static List batchSizes = new ArrayList();
private static int currentBatch = -1;
public StatsBatcher(SQLExceptionHelper exceptionHelper, int jdbcBatchSize) {
super( exceptionHelper, jdbcBatchSize );
public StatsBatch(Object key, SQLStatementLogger statementLogger, SQLExceptionHelper exceptionHelper, int jdbcBatchSize) {
super( key, statementLogger, exceptionHelper, jdbcBatchSize );
}
static void reset() {
@ -91,7 +90,7 @@ public class InsertOrderingTest extends FunctionalTestCase {
batchSQL = null;
}
public void setStatement(String sql, PreparedStatement ps) {
public void addBatchStatement(Object key, String sql, PreparedStatement ps) {
if ( batchSQL == null || ! batchSQL.equals( sql ) ) {
currentBatch++;
batchSQL = sql;
@ -99,31 +98,31 @@ public class InsertOrderingTest extends FunctionalTestCase {
System.out.println( "--------------------------------------------------------" );
System.out.println( "Preparing statement [" + sql + "]" );
}
super.setStatement( sql, ps );
super.addBatchStatement( key, sql, ps );
}
public void addToBatch(Expectation expectation) throws SQLException, HibernateException {
public void addToBatch(Object key, String sql, Expectation expectation) {
Counter counter = ( Counter ) batchSizes.get( currentBatch );
counter.count++;
System.out.println( "Adding to batch [" + batchSQL + "]" );
super.addToBatch( expectation );
super.addToBatch( key, sql, expectation );
}
protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
protected void doExecuteBatch() {
System.out.println( "executing batch [" + batchSQL + "]" );
System.out.println( "--------------------------------------------------------" );
super.doExecuteBatch( ps );
super.doExecuteBatch();
}
}
public static class StatsBatcherFactory implements BatcherFactory {
public static class StatsBatchBuilder extends BatchBuilder {
private int jdbcBatchSize;
public void setJdbcBatchSize(int jdbcBatchSize) {
this.jdbcBatchSize = jdbcBatchSize;
}
public Batcher createBatcher(SQLExceptionHelper exceptionHelper) {
return new StatsBatcher( exceptionHelper, jdbcBatchSize );
public Batch buildBatch(Object key, SQLStatementLogger statementLogger, SQLExceptionHelper exceptionHelper) {
return new StatsBatch(key, statementLogger, exceptionHelper, jdbcBatchSize );
}
}
}

View File

@ -35,7 +35,6 @@ import org.hibernate.ConnectionReleaseMode;
import org.hibernate.engine.jdbc.internal.LogicalConnectionImpl;
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
import org.hibernate.jdbc.NonBatchingBatcherFactory;
import org.hibernate.test.common.BasicTestingJdbcServiceImpl;
import org.hibernate.testing.junit.UnitTestCase;
@ -135,8 +134,7 @@ public class AggressiveReleaseTest extends UnitTestCase {
null,
ConnectionReleaseMode.AFTER_STATEMENT,
services,
null,
new NonBatchingBatcherFactory()
null
);
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
ConnectionCounter observer = new ConnectionCounter();
@ -170,8 +168,7 @@ public class AggressiveReleaseTest extends UnitTestCase {
null,
ConnectionReleaseMode.AFTER_STATEMENT,
services,
null,
new NonBatchingBatcherFactory()
null
);
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
ConnectionCounter observer = new ConnectionCounter();
@ -230,8 +227,7 @@ public class AggressiveReleaseTest extends UnitTestCase {
null,
ConnectionReleaseMode.AFTER_STATEMENT,
services,
null,
new NonBatchingBatcherFactory()
null
);
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
ConnectionCounter observer = new ConnectionCounter();

View File

@ -34,7 +34,6 @@ import org.hibernate.ConnectionReleaseMode;
import org.hibernate.JDBCException;
import org.hibernate.engine.jdbc.internal.LogicalConnectionImpl;
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
import org.hibernate.jdbc.NonBatchingBatcherFactory;
import org.hibernate.test.common.BasicTestingJdbcServiceImpl;
import org.hibernate.testing.junit.UnitTestCase;
@ -63,8 +62,7 @@ public class BasicConnectionProxyTest extends UnitTestCase {
null,
ConnectionReleaseMode.AFTER_TRANSACTION,
services,
null,
new NonBatchingBatcherFactory()
null
);
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
try {
@ -92,8 +90,7 @@ public class BasicConnectionProxyTest extends UnitTestCase {
null,
ConnectionReleaseMode.AFTER_TRANSACTION,
services,
null,
new NonBatchingBatcherFactory()
null
);
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
try {
@ -115,8 +112,7 @@ public class BasicConnectionProxyTest extends UnitTestCase {
null,
ConnectionReleaseMode.AFTER_TRANSACTION,
services,
null,
new NonBatchingBatcherFactory()
null
);
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );

View File

@ -26,7 +26,11 @@ import java.util.List;
import junit.framework.Test;
import junit.framework.Assert;
import org.hibernate.engine.jdbc.batch.internal.BatchBuilder;
import org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
import org.hibernate.testing.junit.functional.FunctionalTestCase;
import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.cfg.Configuration;
@ -35,9 +39,6 @@ import org.hibernate.Session;
import org.hibernate.Hibernate;
import org.hibernate.Interceptor;
import org.hibernate.EmptyInterceptor;
import org.hibernate.jdbc.BatcherFactory;
import org.hibernate.jdbc.NonBatchingBatcher;
import org.hibernate.jdbc.Batcher;
import org.hibernate.stat.CollectionStatistics;
import org.hibernate.loader.collection.BatchingCollectionInitializer;
import org.hibernate.persister.collection.AbstractCollectionPersister;
@ -64,23 +65,23 @@ public class BatchedManyToManyTest extends FunctionalTestCase {
public void configure(Configuration cfg) {
cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" );
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
cfg.setProperty( Environment.BATCH_STRATEGY, TestingBatcherFactory.class.getName() );
cfg.setProperty( Environment.BATCH_STRATEGY, TestingBatchBuilder.class.getName() );
}
public static class TestingBatcherFactory implements BatcherFactory {
public static class TestingBatchBuilder extends BatchBuilder {
private int jdbcBatchSize;
public void setJdbcBatchSize(int jdbcBatchSize) {
this.jdbcBatchSize = jdbcBatchSize;
}
public Batcher createBatcher(SQLExceptionHelper exceptionHelper) {
return new TestingBatcher( exceptionHelper, jdbcBatchSize );
public Batch buildBatch(Object key, SQLStatementLogger statementLogger, SQLExceptionHelper exceptionHelper) {
return new TestingBatch(key, statementLogger, exceptionHelper, jdbcBatchSize );
}
}
public static class TestingBatcher extends NonBatchingBatcher {
public TestingBatcher(SQLExceptionHelper exceptionHelper, int jdbcBatchSize) {
super( exceptionHelper );
public static class TestingBatch extends NonBatchingBatch {
public TestingBatch(Object key, SQLStatementLogger statementLogger, SQLExceptionHelper exceptionHelper, int jdbcBatchSize) {
super( key, statementLogger, exceptionHelper );
}
}

View File

@ -8,10 +8,12 @@ log4j.rootLogger=info, stdout
log4j.logger.org.hibernate.test=info
log4j.logger.org.hibernate.tool.hbm2ddl=debug
log4j.logger.org.hibernate.engine.jdbc=trace
log4j.logger.org.hibernate.engine.jdbc.internal=trace
log4j.logger.org.hibernate.engine.jdbc.internal.proxy=trace
log4j.logger.org.hibernate.engine.jdbc.batch.internal=trace
log4j.logger.org.hibernate.hql.ast.QueryTranslatorImpl=trace
log4j.logger.org.hibernate.hql.ast.HqlSqlWalker=trace
log4j.logger.org.hibernate.hql.ast.SqlGenerator=trace
log4j.logger.org.hibernate.hql.ast.AST=trace
log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace
log4j.logger.org.hibernate.type.BasicTypeRegistry=trace
log4j.logger.org.hibernate.type.BasicTypeRegistry=trace