Merge branch 'HHH-5778-batch'
This commit is contained in:
commit
66f8e90e7c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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." );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue