Merge branch 'master' of github.com:hibernate/hibernate-core

This commit is contained in:
Strong Liu 2011-03-04 23:28:52 +08:00
commit 1dc88b3c38
213 changed files with 8864 additions and 6424 deletions

View File

@ -67,6 +67,7 @@ libraries = [
jcl: 'commons-logging:commons-logging:99.0-does-not-exist', jcl: 'commons-logging:commons-logging:99.0-does-not-exist',
// testing // testing
atomikos: 'com.atomikos:transactions-jdbc:3.7.0',
junit: 'junit:junit:3.8.2', junit: 'junit:junit:3.8.2',
testng: 'org.testng:testng:5.8:jdk15', testng: 'org.testng:testng:5.8:jdk15',
jpa_modelgen: 'org.hibernate:hibernate-jpamodelgen:1.1.0.Final', jpa_modelgen: 'org.hibernate:hibernate-jpamodelgen:1.1.0.Final',
@ -106,6 +107,7 @@ subprojects { subProject ->
dependencies { dependencies {
compile( libraries.slf4j_api ) compile( libraries.slf4j_api )
testCompile( libraries.junit ) testCompile( libraries.junit )
testCompile( libraries.atomikos )
testRuntime( libraries.slf4j_simple ) testRuntime( libraries.slf4j_simple )
testRuntime( libraries.jcl_slf4j ) testRuntime( libraries.jcl_slf4j )
testRuntime( libraries.jcl_api ) testRuntime( libraries.jcl_api )
@ -151,12 +153,8 @@ subprojects { subProject ->
sourceCompatibility = "1.6" sourceCompatibility = "1.6"
ideaModule { ideaModule {
// treat our "provided" configuration dependencies as "Compile" scope dependencies in IntelliJ // treat our "provided" configuration dependencies as "compile" scope dependencies in IntelliJ
scopes.COMPILE.plus.add( configurations.provided ) scopes.COMPILE.plus.add( configurations.provided )
// Use explicitly separate compilation output directories for Gradle and IntelliJ
File baseDirectory = new File( subProject.buildDir, "idea/classes" )
outputDir = new File( baseDirectory, "main" )
testOutputDir = new File( baseDirectory, "test" )
whenConfigured { module -> whenConfigured { module ->
module.dependencies*.exported = true module.dependencies*.exported = true
} }

View File

@ -96,4 +96,9 @@ task installTesting(type:Upload, dependsOn: [testingJar,testingSourcesJar]) {
} }
install.dependsOn installTesting install.dependsOn installTesting
uploadTesting.dependsOn installTesting uploadTesting.dependsOn installTesting
// temporary
test {
ignoreFailures = true
}

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,7 +20,6 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate; package org.hibernate;
@ -35,6 +34,9 @@ package org.hibernate;
* @author Gavin King * @author Gavin King
*/ */
public class HibernateException extends RuntimeException { public class HibernateException extends RuntimeException {
public HibernateException(String s) {
super(s);
}
public HibernateException(Throwable root) { public HibernateException(Throwable root) {
super(root); super(root);
@ -43,10 +45,6 @@ public class HibernateException extends RuntimeException {
public HibernateException(String string, Throwable root) { public HibernateException(String string, Throwable root) {
super(string, root); super(string, root);
} }
public HibernateException(String s) {
super(s);
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,22 +20,20 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.transaction; package org.hibernate;
/** /**
* {@link TransactionManagerLookup} strategy for JRun4 AS * Indicates an attempt was made to use a closed resource (Session, SessionFactory, etc).
* *
* @author Joseph Bissen * @author Steve Ebersole
*/ */
public class JRun4TransactionManagerLookup extends JNDITransactionManagerLookup { public class ResourceClosedException extends HibernateException {
public ResourceClosedException(String s) {
protected String getName() { super( s );
return "java:/TransactionManager";
} }
public String getUserTransactionName() { public ResourceClosedException(String string, Throwable root) {
return "java:comp/UserTransaction"; super( string, root );
} }
} }

View File

@ -119,8 +119,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* for use. * for use.
* <p/> * <p/>
* Note that for backwards compatibility, if a {@link org.hibernate.context.CurrentSessionContext} * Note that for backwards compatibility, if a {@link org.hibernate.context.CurrentSessionContext}
* is not configured but a JTA {@link org.hibernate.transaction.TransactionManagerLookup} * is not configured but JTA is configured this will default to the {@link org.hibernate.context.JTASessionContext}
* is configured this will default to the {@link org.hibernate.context.JTASessionContext}
* impl. * impl.
* *
* @return The current session. * @return The current session.

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,109 +20,140 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate; package org.hibernate;
import org.hibernate.engine.transaction.spi.LocalStatus;
import javax.transaction.Synchronization; import javax.transaction.Synchronization;
/** /**
* Allows the application to define units of work, while * Defines the contract for abstracting applications from the configured underlying means of transaction management.
* maintaining abstraction from the underlying transaction * Allows the application to define units of work, while maintaining abstraction from the underlying transaction
* implementation (eg. JTA, JDBC).<br> * implementation (eg. JTA, JDBC).
* <br> * <p/>
* A transaction is associated with a <tt>Session</tt> and is * A transaction is associated with a {@link Session} and is usually initiated by a call to
* usually instantiated by a call to <tt>Session.beginTransaction()</tt>. * {@link org.hibernate.Session#beginTransaction()}. A single session might span multiple transactions since
* A single session might span multiple transactions since * the notion of a session (a conversation between the application and the datastore) is of coarser granularity than
* the notion of a session (a conversation between the application * the notion of a transaction. However, it is intended that there be at most one uncommitted transaction associated
* and the datastore) is of coarser granularity than the notion of * with a particular {@link Session} at any time.
* a transaction. However, it is intended that there be at most one * <p/>
* uncommitted <tt>Transaction</tt> associated with a particular * Implementers are not intended to be thread-safe.
* <tt>Session</tt> at any time.<br>
* <br>
* Implementors are not intended to be threadsafe.
* *
* @see Session#beginTransaction()
* @see org.hibernate.transaction.TransactionFactory
* @author Anton van Straaten * @author Anton van Straaten
* @author Steve Ebersole
*/ */
public interface Transaction { public interface Transaction {
/** /**
* Begin a new transaction. * Is this transaction the initiator of any underlying transaction?
*
* @return {@literal true} if this transaction initiated the underlying transaction; {@literal false} otherwise.
*/ */
public void begin() throws HibernateException; public boolean isInitiator();
/** /**
* Flush the associated <tt>Session</tt> and end the unit of work (unless * Begin this transaction. No-op if the transaction has already been begun. Note that this is not necessarily
* we are in {@link FlushMode#MANUAL}. * symmetrical since usually multiple calls to {@link #commit} or {@link #rollback} will error.
* </p>
* This method will commit the underlying transaction if and only
* if the underlying transaction was initiated by this object.
* *
* @throws HibernateException * @throws HibernateException Indicates a problem beginning the transaction.
*/ */
public void commit() throws HibernateException; public void begin();
/** /**
* Force the underlying transaction to roll back. * Commit this transaction. This might entail a number of things depending on the context:<ul>
* <li>
* If this transaction is the {@link #isInitiator initiator}, {@link Session#flush} the {@link Session}
* with which it is associated (unless {@link Session} is in {@link FlushMode#MANUAL}).
* </li>
* <li>
* If this transaction is the {@link #isInitiator initiator}, commit the underlying transaction.
* </li>
* <li>
* Coordinate various callbacks
* </li>
* </ul>
* *
* @throws HibernateException * @throws HibernateException Indicates a problem committing the transaction.
*/ */
public void rollback() throws HibernateException; public void commit();
/**
* Rollback this transaction. Either rolls back the underlying transaction or ensures it cannot later commit
* (depending on the actual underlying strategy).
*
* @throws HibernateException Indicates a problem rolling back the transaction.
*/
public void rollback();
/**
* Get the current local status of this transaction.
* <p/>
* This only accounts for the local view of the transaction status. In other words it does not check the status
* of the actual underlying transaction.
*
* @return The current local status.
*/
public LocalStatus getLocalStatus();
/**
* Is this transaction still active?
* <p/>
* Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a
* transaction is active when it is initiated directly through the JDBC {@link java.sql.Connection}, only when
* it is initiated from here.
*
* @return {@literal true} if the transaction is still active; {@literal false} otherwise.
*
* @throws HibernateException Indicates a problem checking the transaction status.
*/
public boolean isActive();
/**
* Was this transaction committed?
* <p/>
* Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a
* transaction was committed when the commit was performed directly through the JDBC {@link java.sql.Connection},
* only when the commit was done from this.
*
* @return {@literal true} if the transaction is rolled back; {@literal false} otherwise.
*
* @throws HibernateException Indicates a problem checking the transaction status.
*/
public boolean wasCommitted();
/** /**
* Was this transaction rolled back or set to rollback only? * Was this transaction rolled back or set to rollback only?
* <p/> * <p/>
* This only accounts for actions initiated from this local transaction. * Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a
* If, for example, the underlying transaction is forced to rollback via * transaction was rolled back when rollback was performed directly through the JDBC {@link java.sql.Connection},
* some other means, this method still reports false because the rollback * only when it was rolled back from here.
* was not initiated from here.
* *
* @return boolean True if the transaction was rolled back via this * @return {@literal true} if the transaction is rolled back; {@literal false} otherwise.
* local transaction; false otherwise.
* @throws HibernateException
*/
public boolean wasRolledBack() throws HibernateException;
/**
* Check if this transaction was successfully committed.
* <p/>
* This method could return <tt>false</tt> even after successful invocation
* of {@link #commit}. As an example, JTA based strategies no-op on
* {@link #commit} calls if they did not start the transaction; in that case,
* they also report {@link #wasCommitted} as false.
* *
* @return boolean True if the transaction was (unequivocally) committed * @throws HibernateException Indicates a problem checking the transaction status.
* via this local transaction; false otherwise.
* @throws HibernateException
*/ */
public boolean wasCommitted() throws HibernateException; public boolean wasRolledBack();
/**
* Is this transaction still active?
* <p/>
* Again, this only returns information in relation to the
* local transaction, not the actual underlying transaction.
*
* @return boolean Treu if this local transaction is still active.
*/
public boolean isActive() throws HibernateException;
/** /**
* Register a user synchronization callback for this transaction. * Register a user synchronization callback for this transaction.
* *
* @param synchronization The Synchronization callback to register. * @param synchronization The Synchronization callback to register.
* @throws HibernateException *
* @throws HibernateException Indicates a problem registering the synchronization.
*/ */
public void registerSynchronization(Synchronization synchronization) public void registerSynchronization(Synchronization synchronization) throws HibernateException;
throws HibernateException;
/** /**
* Set the transaction timeout for any transaction started by * Set the transaction timeout for any transaction started by a subsequent call to {@link #begin} on this instance.
* a subsequent call to <tt>begin()</tt> on this instance.
* *
* @param seconds The number of seconds before a timeout. * @param seconds The number of seconds before a timeout.
*/ */
public void setTimeout(int seconds); public void setTimeout(int seconds);
/**
* Retrieve the transaction timeout set for this transaction. A negative indicates no timeout has been set.
*
* @return The timeout, in seconds.
*/
public int getTimeout();
} }

View File

@ -1842,7 +1842,7 @@ public class Configuration implements Serializable {
Properties copy = new Properties(); Properties copy = new Properties();
copy.putAll( properties ); copy.putAll( properties );
ConfigurationHelper.resolvePlaceHolders( copy ); ConfigurationHelper.resolvePlaceHolders( copy );
Settings settings = buildSettings( copy, serviceRegistry.getService( JdbcServices.class ) ); Settings settings = buildSettings( copy, serviceRegistry );
return new SessionFactoryImpl( return new SessionFactoryImpl(
this, this,
@ -2825,18 +2825,18 @@ public class Configuration implements Serializable {
* *
* @return The build settings * @return The build settings
*/ */
public Settings buildSettings(JdbcServices jdbcServices) { public Settings buildSettings(ServiceRegistry serviceRegistry) {
Properties clone = ( Properties ) properties.clone(); Properties clone = ( Properties ) properties.clone();
ConfigurationHelper.resolvePlaceHolders( clone ); ConfigurationHelper.resolvePlaceHolders( clone );
return buildSettingsInternal( clone, jdbcServices ); return buildSettingsInternal( clone, serviceRegistry );
} }
public Settings buildSettings(Properties props, JdbcServices jdbcServices) throws HibernateException { public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException {
return buildSettingsInternal( props, jdbcServices ); return buildSettingsInternal( props, serviceRegistry );
} }
private Settings buildSettingsInternal(Properties props, JdbcServices jdbcServices) { private Settings buildSettingsInternal(Properties props, ServiceRegistry serviceRegistry) {
final Settings settings = settingsFactory.buildSettings( props, jdbcServices ); final Settings settings = settingsFactory.buildSettings( props, serviceRegistry );
settings.setEntityTuplizerFactory( this.getEntityTuplizerFactory() ); settings.setEntityTuplizerFactory( this.getEntityTuplizerFactory() );
// settings.setComponentTuplizerFactory( this.getComponentTuplizerFactory() ); // settings.setComponentTuplizerFactory( this.getComponentTuplizerFactory() );
return settings; return settings;

View File

@ -164,7 +164,7 @@ import org.hibernate.util.ConfigHelper;
* <tr> * <tr>
* <td><tt>hibernate.transaction.factory_class</tt></td> * <td><tt>hibernate.transaction.factory_class</tt></td>
* <td>the factory to use for instantiating <tt>Transaction</tt>s. * <td>the factory to use for instantiating <tt>Transaction</tt>s.
* (Defaults to <tt>JDBCTransactionFactory</tt>.)</td> * (Defaults to <tt>JdbcTransactionFactory</tt>.)</td>
* </tr> * </tr>
* <tr> * <tr>
* <td><tt>hibernate.query.substitutions</tt></td><td>query language token substitutions</td> * <td><tt>hibernate.query.substitutions</tt></td><td>query language token substitutions</td>
@ -376,7 +376,8 @@ public final class Environment {
*/ */
public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class"; public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class";
/** /**
* <tt>TransactionFactory</tt> implementor to use for creating <tt>Transaction</tt>s * Names the implementation of {@link org.hibernate.engine.transaction.spi.TransactionContext} to use for
* creating {@link org.hibernate.Transaction} instances
*/ */
public static final String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class"; public static final String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class";
/** /**

View File

@ -23,20 +23,18 @@
*/ */
package org.hibernate.cfg; package org.hibernate.cfg;
import java.util.Map;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.cache.QueryCacheFactory; import org.hibernate.cache.QueryCacheFactory;
import org.hibernate.cache.RegionFactory; import org.hibernate.cache.RegionFactory;
import org.hibernate.engine.jdbc.JdbcSupport; import org.hibernate.engine.jdbc.JdbcSupport;
import org.hibernate.engine.jdbc.batch.internal.BatchBuilder;
import org.hibernate.hql.QueryTranslatorFactory; import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.jdbc.util.SQLStatementLogger; import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.transaction.TransactionFactory; import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.transaction.TransactionManagerLookup;
import org.hibernate.tuple.entity.EntityTuplizerFactory; import org.hibernate.tuple.entity.EntityTuplizerFactory;
import java.util.Map;
/** /**
* Settings that affect the behaviour of Hibernate at runtime. * Settings that affect the behaviour of Hibernate at runtime.
* *
@ -75,9 +73,6 @@ public final class Settings {
private ConnectionReleaseMode connectionReleaseMode; private ConnectionReleaseMode connectionReleaseMode;
private RegionFactory regionFactory; private RegionFactory regionFactory;
private QueryCacheFactory queryCacheFactory; private QueryCacheFactory queryCacheFactory;
private TransactionFactory transactionFactory;
private TransactionManagerLookup transactionManagerLookup;
private BatchBuilder batchBuilder;
private QueryTranslatorFactory queryTranslatorFactory; private QueryTranslatorFactory queryTranslatorFactory;
private boolean wrapResultSetsEnabled; private boolean wrapResultSetsEnabled;
private boolean orderUpdatesEnabled; private boolean orderUpdatesEnabled;
@ -94,6 +89,8 @@ public final class Settings {
private JdbcSupport jdbcSupport; private JdbcSupport jdbcSupport;
private String importFiles; private String importFiles;
private JtaPlatform jtaPlatform;
/** /**
* Package protected constructor * Package protected constructor
*/ */
@ -162,10 +159,6 @@ public final class Settings {
return jdbcFetchSize; return jdbcFetchSize;
} }
public TransactionFactory getTransactionFactory() {
return transactionFactory;
}
public String getSessionFactoryName() { public String getSessionFactoryName() {
return sessionFactoryName; return sessionFactoryName;
} }
@ -190,10 +183,6 @@ public final class Settings {
return regionFactory; return regionFactory;
} }
public TransactionManagerLookup getTransactionManagerLookup() {
return transactionManagerLookup;
}
public boolean isQueryCacheEnabled() { public boolean isQueryCacheEnabled() {
return queryCacheEnabled; return queryCacheEnabled;
} }
@ -226,10 +215,6 @@ public final class Settings {
return flushBeforeCompletionEnabled; return flushBeforeCompletionEnabled;
} }
public BatchBuilder getBatchBuilder() {
return batchBuilder;
}
public boolean isAutoCloseSessionEnabled() { public boolean isAutoCloseSessionEnabled() {
return autoCloseSessionEnabled; return autoCloseSessionEnabled;
} }
@ -349,10 +334,6 @@ public final class Settings {
jdbcFetchSize = integer; jdbcFetchSize = integer;
} }
void setTransactionFactory(TransactionFactory factory) {
transactionFactory = factory;
}
void setSessionFactoryName(String string) { void setSessionFactoryName(String string) {
sessionFactoryName = string; sessionFactoryName = string;
} }
@ -377,10 +358,6 @@ public final class Settings {
this.regionFactory = regionFactory; this.regionFactory = regionFactory;
} }
void setTransactionManagerLookup(TransactionManagerLookup lookup) {
transactionManagerLookup = lookup;
}
void setQueryCacheEnabled(boolean b) { void setQueryCacheEnabled(boolean b) {
queryCacheEnabled = b; queryCacheEnabled = b;
} }
@ -413,10 +390,6 @@ public final class Settings {
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled; this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
} }
void setBatcherBuilder(BatchBuilder batchBuilder) {
this.batchBuilder = batchBuilder;
}
void setAutoCloseSessionEnabled(boolean autoCloseSessionEnabled) { void setAutoCloseSessionEnabled(boolean autoCloseSessionEnabled) {
this.autoCloseSessionEnabled = autoCloseSessionEnabled; this.autoCloseSessionEnabled = autoCloseSessionEnabled;
} }
@ -496,4 +469,13 @@ public final class Settings {
// void setBytecodeProvider(BytecodeProvider bytecodeProvider) { // void setBytecodeProvider(BytecodeProvider bytecodeProvider) {
// this.bytecodeProvider = bytecodeProvider; // this.bytecodeProvider = bytecodeProvider;
// } // }
public JtaPlatform getJtaPlatform() {
return jtaPlatform;
}
void setJtaPlatform(JtaPlatform jtaPlatform) {
this.jtaPlatform = jtaPlatform;
}
} }

View File

@ -39,16 +39,14 @@ import org.hibernate.cache.QueryCacheFactory;
import org.hibernate.cache.RegionFactory; import org.hibernate.cache.RegionFactory;
import org.hibernate.cache.impl.NoCachingRegionFactory; import org.hibernate.cache.impl.NoCachingRegionFactory;
import org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge; import org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge;
import org.hibernate.engine.jdbc.batch.internal.BatchBuilder;
import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.transaction.spi.TransactionFactory;
import org.hibernate.hql.QueryTranslatorFactory; import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jdbc.util.SQLStatementLogger; import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.transaction.TransactionFactory; import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.transaction.TransactionFactoryFactory; import org.hibernate.service.spi.ServiceRegistry;
import org.hibernate.transaction.TransactionManagerLookup;
import org.hibernate.transaction.TransactionManagerLookupFactory;
import org.hibernate.util.ReflectHelper; import org.hibernate.util.ReflectHelper;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
@ -66,7 +64,8 @@ public class SettingsFactory implements Serializable {
protected SettingsFactory() { protected SettingsFactory() {
} }
public Settings buildSettings(Properties props, JdbcServices jdbcServices) { public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) {
final JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class );
Settings settings = new Settings(); Settings settings = new Settings();
//SessionFactory name: //SessionFactory name:
@ -90,10 +89,7 @@ public class SettingsFactory implements Serializable {
settings.setJdbcSupport( new JdbcSupport( ! ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, properties ) ) ); settings.setJdbcSupport( new JdbcSupport( ! ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, properties ) ) );
// Transaction settings: // Transaction settings:
settings.setJtaPlatform( serviceRegistry.getService( JtaPlatform.class ) );
TransactionFactory transactionFactory = createTransactionFactory(properties);
settings.setTransactionFactory(transactionFactory);
settings.setTransactionManagerLookup( createTransactionManagerLookup(properties) );
boolean flushBeforeCompletion = ConfigurationHelper.getBoolean(Environment.FLUSH_BEFORE_COMPLETION, properties); boolean flushBeforeCompletion = ConfigurationHelper.getBoolean(Environment.FLUSH_BEFORE_COMPLETION, properties);
log.info("Automatic flush during beforeCompletion(): " + enabledDisabled(flushBeforeCompletion) ); log.info("Automatic flush during beforeCompletion(): " + enabledDisabled(flushBeforeCompletion) );
@ -112,7 +108,6 @@ public class SettingsFactory implements Serializable {
boolean jdbcBatchVersionedData = ConfigurationHelper.getBoolean(Environment.BATCH_VERSIONED_DATA, properties, false); boolean jdbcBatchVersionedData = ConfigurationHelper.getBoolean(Environment.BATCH_VERSIONED_DATA, properties, false);
if (batchSize>0) log.info("JDBC batch updates for versioned data: " + enabledDisabled(jdbcBatchVersionedData) ); if (batchSize>0) log.info("JDBC batch updates for versioned data: " + enabledDisabled(jdbcBatchVersionedData) );
settings.setJdbcBatchVersionedData(jdbcBatchVersionedData); settings.setJdbcBatchVersionedData(jdbcBatchVersionedData);
settings.setBatcherBuilder( createBatchBuilder(properties, batchSize) );
boolean useScrollableResultSets = ConfigurationHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, meta.supportsScrollableResults()); boolean useScrollableResultSets = ConfigurationHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, meta.supportsScrollableResults());
log.info("Scrollable result sets: " + enabledDisabled(useScrollableResultSets) ); log.info("Scrollable result sets: " + enabledDisabled(useScrollableResultSets) );
@ -134,7 +129,7 @@ public class SettingsFactory implements Serializable {
log.info( "Connection release mode: " + releaseModeName ); log.info( "Connection release mode: " + releaseModeName );
ConnectionReleaseMode releaseMode; ConnectionReleaseMode releaseMode;
if ( "auto".equals(releaseModeName) ) { if ( "auto".equals(releaseModeName) ) {
releaseMode = transactionFactory.getDefaultReleaseMode(); releaseMode = serviceRegistry.getService( TransactionFactory.class ).getDefaultReleaseMode();
} }
else { else {
releaseMode = ConnectionReleaseMode.parse( releaseModeName ); releaseMode = ConnectionReleaseMode.parse( releaseModeName );
@ -301,7 +296,9 @@ public class SettingsFactory implements Serializable {
} }
public static RegionFactory createRegionFactory(Properties properties, boolean cachingEnabled) { public static RegionFactory createRegionFactory(Properties properties, boolean cachingEnabled) {
String regionFactoryClassName = ConfigurationHelper.getString( Environment.CACHE_REGION_FACTORY, properties, null ); String regionFactoryClassName = ConfigurationHelper.getString(
Environment.CACHE_REGION_FACTORY, properties, null
);
if ( regionFactoryClassName == null && cachingEnabled ) { if ( regionFactoryClassName == null && cachingEnabled ) {
String providerClassName = ConfigurationHelper.getString( Environment.CACHE_PROVIDER, properties, null ); String providerClassName = ConfigurationHelper.getString( Environment.CACHE_PROVIDER, properties, null );
if ( providerClassName != null ) { if ( providerClassName != null ) {
@ -346,33 +343,4 @@ public class SettingsFactory implements Serializable {
} }
} }
protected BatchBuilder createBatchBuilder(Properties properties, int batchSize) {
String batchBuilderClass = properties.getProperty(Environment.BATCH_STRATEGY);
BatchBuilder batchBuilder;
if (batchBuilderClass==null) {
batchBuilder = batchSize > 0
? new BatchBuilder( batchSize )
: new BatchBuilder();
}
else {
log.info("Batch factory: " + batchBuilderClass);
try {
batchBuilder = (BatchBuilder) ReflectHelper.classForName(batchBuilderClass).newInstance();
}
catch (Exception cnfe) {
throw new HibernateException("could not instantiate BatchBuilder: " + batchBuilderClass, cnfe);
}
}
batchBuilder.setJdbcBatchSize( batchSize );
return batchBuilder;
}
protected TransactionFactory createTransactionFactory(Properties properties) {
return TransactionFactoryFactory.buildTransactionFactory(properties);
}
protected TransactionManagerLookup createTransactionManagerLookup(Properties properties) {
return TransactionManagerLookupFactory.getTransactionManagerLookup(properties);
}
} }

View File

@ -28,7 +28,8 @@ import org.hibernate.HibernateException;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.classic.Session; import org.hibernate.classic.Session;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.util.JTAHelper; import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -76,7 +77,8 @@ public class JTASessionContext implements CurrentSessionContext {
* {@inheritDoc} * {@inheritDoc}
*/ */
public Session currentSession() throws HibernateException { public Session currentSession() throws HibernateException {
TransactionManager transactionManager = factory.getTransactionManager(); final JtaPlatform jtaPlatform = factory.getServiceRegistry().getService( JtaPlatform.class );
final TransactionManager transactionManager = jtaPlatform.retrieveTransactionManager();
if ( transactionManager == null ) { if ( transactionManager == null ) {
throw new HibernateException( "No TransactionManagerLookup specified" ); throw new HibernateException( "No TransactionManagerLookup specified" );
} }
@ -87,9 +89,9 @@ public class JTASessionContext implements CurrentSessionContext {
if ( txn == null ) { if ( txn == null ) {
throw new HibernateException( "Unable to locate current JTA transaction" ); throw new HibernateException( "Unable to locate current JTA transaction" );
} }
if ( !JTAHelper.isInProgress( txn.getStatus() ) ) { if ( !JtaStatusHelper.isActive( txn.getStatus() ) ) {
// We could register the session against the transaction even though it is // We could register the session against the transaction even though it is
// not started, but we'd have no guarentee of ever getting the map // not started, but we'd have no guarantee of ever getting the map
// entries cleaned up (aside from spawning threads). // entries cleaned up (aside from spawning threads).
throw new HibernateException( "Current transaction is not in progress" ); throw new HibernateException( "Current transaction is not in progress" );
} }
@ -101,9 +103,7 @@ public class JTASessionContext implements CurrentSessionContext {
throw new HibernateException( "Problem locating/validating JTA transaction", t ); throw new HibernateException( "Problem locating/validating JTA transaction", t );
} }
final Object txnIdentifier = factory.getSettings().getTransactionManagerLookup() == null final Object txnIdentifier = jtaPlatform.getTransactionIdentifier( txn );
? txn
: factory.getSettings().getTransactionManagerLookup().getTransactionIdentifier( txn );
Session currentSession = ( Session ) currentSessionMap.get( txnIdentifier ); Session currentSession = ( Session ) currentSessionMap.get( txnIdentifier );

View File

@ -43,6 +43,10 @@ import org.hibernate.HibernateException;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.classic.Session; import org.hibernate.classic.Session;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.event.EventSource;
/** /**
* A {@link CurrentSessionContext} impl which scopes the notion of current * A {@link CurrentSessionContext} impl which scopes the notion of current
@ -74,11 +78,11 @@ public class ThreadLocalSessionContext implements CurrentSessionContext {
private static final Logger log = LoggerFactory.getLogger( ThreadLocalSessionContext.class ); private static final Logger log = LoggerFactory.getLogger( ThreadLocalSessionContext.class );
private static final Class[] SESSION_PROXY_INTERFACES = new Class[] { private static final Class[] SESSION_PROXY_INTERFACES = new Class[] {
org.hibernate.classic.Session.class, Session.class,
org.hibernate.engine.SessionImplementor.class, SessionImplementor.class,
org.hibernate.engine.jdbc.spi.JDBCContext.Context.class, EventSource.class,
org.hibernate.event.EventSource.class, TransactionContext.class,
org.hibernate.engine.jdbc.LobCreationContext.class LobCreationContext.class
}; };
/** /**

View File

@ -78,7 +78,7 @@ public class PessimisticReadSelectLockingStrategy extends AbstractSelectLockingS
final String sql = determineSql( timeout ); final String sql = determineSql( timeout );
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session ); getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
if ( getLockable().isVersioned() ) { if ( getLockable().isVersioned() ) {

View File

@ -94,7 +94,7 @@ public class PessimisticReadUpdateLockingStrategy implements LockingStrategy {
} }
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
lockable.getVersionType().nullSafeSet( st, version, 1, session ); lockable.getVersionType().nullSafeSet( st, version, 1, session );
int offset = 2; int offset = 2;

View File

@ -78,7 +78,7 @@ public class PessimisticWriteSelectLockingStrategy extends AbstractSelectLocking
final String sql = determineSql( timeout ); final String sql = determineSql( timeout );
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session ); getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
if ( getLockable().isVersioned() ) { if ( getLockable().isVersioned() ) {

View File

@ -94,7 +94,7 @@ public class PessimisticWriteUpdateLockingStrategy implements LockingStrategy {
} }
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
lockable.getVersionType().nullSafeSet( st, version, 1, session ); lockable.getVersionType().nullSafeSet( st, version, 1, session );
int offset = 2; int offset = 2;

View File

@ -73,7 +73,7 @@ public class SelectLockingStrategy extends AbstractSelectLockingStrategy {
final String sql = determineSql( timeout ); final String sql = determineSql( timeout );
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session ); getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
if ( getLockable().isVersioned() ) { if ( getLockable().isVersioned() ) {

View File

@ -92,7 +92,7 @@ public class UpdateLockingStrategy implements LockingStrategy {
// todo : should we additionally check the current isolation mode explicitly? // todo : should we additionally check the current isolation mode explicitly?
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
lockable.getVersionType().nullSafeSet( st, version, 1, session ); lockable.getVersionType().nullSafeSet( st, version, 1, session );
int offset = 2; int offset = 2;

View File

@ -265,7 +265,7 @@ public class ActionQueue {
execute( ( Executable ) list.get( i ) ); execute( ( Executable ) list.get( i ) );
} }
list.clear(); list.clear();
session.getJDBCContext().getConnectionManager().executeBatch(); session.getTransactionCoordinator().getJdbcCoordinator().executeBatch();
} }
public void execute(Executable executable) { public void execute(Executable executable) {

View File

@ -52,6 +52,7 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.SQLFunctionRegistry; import org.hibernate.dialect.function.SQLFunctionRegistry;
import org.hibernate.exception.SQLExceptionConverter; import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
import org.hibernate.service.spi.ServiceRegistry;
import org.hibernate.stat.StatisticsImplementor; import org.hibernate.stat.StatisticsImplementor;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver; import org.hibernate.type.TypeResolver;
@ -145,13 +146,6 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
*/ */
public String getImportedClassName(String name); public String getImportedClassName(String name);
/**
* Get the JTA transaction manager
*/
public TransactionManager getTransactionManager();
/** /**
* Get the default query cache * Get the default query cache
*/ */
@ -262,4 +256,5 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
*/ */
public FetchProfile getFetchProfile(String name); public FetchProfile getFetchProfile(String name);
public ServiceRegistry getServiceRegistry();
} }

View File

@ -39,9 +39,9 @@ import org.hibernate.Query;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.engine.jdbc.spi.JDBCContext;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification; import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.collection.PersistentCollection; import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.event.EventListeners; import org.hibernate.event.EventListeners;
import org.hibernate.impl.CriteriaImpl; import org.hibernate.impl.CriteriaImpl;
import org.hibernate.loader.custom.CustomQuery; import org.hibernate.loader.custom.CustomQuery;
@ -157,20 +157,6 @@ public interface SessionImplementor extends Serializable {
*/ */
public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException; public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException;
/**
* Notify the session that the transaction completed, so we no longer
* own the old locks. (Also we should release cache softlocks.) May
* be called multiple times during the transaction completion process.
* Also called after an autocommit, in which case the second argument
* is null.
*/
public void afterTransactionCompletion(boolean successful, Transaction tx);
/**
* Notify the session that the transaction is about to complete
*/
public void beforeTransactionCompletion(Transaction tx);
/** /**
* Return the identifier of the persistent object, or null if * Return the identifier of the persistent object, or null if
* not associated with the session * not associated with the session
@ -340,11 +326,16 @@ public interface SessionImplementor extends Serializable {
*/ */
public void setFetchProfile(String name); public void setFetchProfile(String name);
public JDBCContext getJDBCContext(); /**
* Retrieve access to the session's transaction coordinator.
*
* @return The transaction coordinator.
*/
public TransactionCoordinator getTransactionCoordinator();
/** /**
* Determine whether the session is closed. Provided seperately from * Determine whether the session is closed. Provided separately from
* {@link #isOpen()} as this method does not attempt any JTA synch * {@link #isOpen()} as this method does not attempt any JTA synchronization
* registration, where as {@link #isOpen()} does; which makes this one * registration, where as {@link #isOpen()} does; which makes this one
* nicer to use for most internal purposes. * nicer to use for most internal purposes.
* *

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,19 +20,16 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.engine; package org.hibernate.engine;
import org.hibernate.HibernateException;
import org.hibernate.jdbc.Work;
import java.io.Serializable; import java.io.Serializable;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.engine.transaction.IsolatedWork;
import org.hibernate.engine.transaction.Isolater;
import org.hibernate.exception.JDBCExceptionHelper;
/** /**
* Allows work to be done outside the current transaction, by suspending it, * Allows work to be done outside the current transaction, by suspending it,
* and performing work in a new transaction * and performing work in a new transaction
@ -41,7 +38,7 @@ import org.hibernate.exception.JDBCExceptionHelper;
*/ */
public abstract class TransactionHelper { public abstract class TransactionHelper {
// todo : remove this and just have subclasses use Isolater/IsolatedWork directly... // todo : remove this and just have subclasses use IsolationDelegate directly...
/** /**
* The work to be done * The work to be done
@ -51,26 +48,27 @@ public abstract class TransactionHelper {
/** /**
* Suspend the current transaction and perform work in a new transaction * Suspend the current transaction and perform work in a new transaction
*/ */
public Serializable doWorkInNewTransaction(final SessionImplementor session) public Serializable doWorkInNewTransaction(final SessionImplementor session) throws HibernateException {
throws HibernateException { class WorkToDo implements Work {
class Work implements IsolatedWork {
Serializable generatedValue; Serializable generatedValue;
public void doWork(Connection connection) throws HibernateException {
@Override
public void execute(Connection connection) throws SQLException {
String sql = null; String sql = null;
try { try {
generatedValue = doWorkInCurrentTransaction( connection, sql ); generatedValue = doWorkInCurrentTransaction( connection, sql );
} }
catch( SQLException sqle ) { catch( SQLException e ) {
throw session.getFactory().getSQLExceptionHelper().convert( throw session.getFactory().getSQLExceptionHelper().convert(
sqle, e,
"could not get or update next value", "could not get or update next value",
sql sql
); );
} }
} }
} }
Work work = new Work(); WorkToDo work = new WorkToDo();
Isolater.doIsolatedWork( work, session ); session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork( work, true );
return work.generatedValue; return work.generatedValue;
} }
} }

View File

@ -23,19 +23,20 @@
*/ */
package org.hibernate.engine.jdbc.batch.internal; package org.hibernate.engine.jdbc.batch.internal;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.engine.jdbc.batch.spi.BatchObserver;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import org.slf4j.Logger;
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.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
/** /**
* Convenience base class for implementors of the Batch interface. * Convenience base class for implementors of the Batch interface.
* *
@ -44,21 +45,20 @@ import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
public abstract class AbstractBatchImpl implements Batch { public abstract class AbstractBatchImpl implements Batch {
private static final Logger log = LoggerFactory.getLogger( AbstractBatchImpl.class ); private static final Logger log = LoggerFactory.getLogger( AbstractBatchImpl.class );
private final SQLStatementLogger statementLogger; private final BatchKey key;
private final SQLExceptionHelper exceptionHelper; private final JdbcCoordinator jdbcCoordinator;
private Object key;
private LinkedHashMap<String,PreparedStatement> statements = new LinkedHashMap<String,PreparedStatement>(); private LinkedHashMap<String,PreparedStatement> statements = new LinkedHashMap<String,PreparedStatement>();
private LinkedHashSet<BatchObserver> observers = new LinkedHashSet<BatchObserver>(); private LinkedHashSet<BatchObserver> observers = new LinkedHashSet<BatchObserver>();
protected AbstractBatchImpl(Object key, protected AbstractBatchImpl(BatchKey key, JdbcCoordinator jdbcCoordinator) {
SQLStatementLogger statementLogger, if ( key == null ) {
SQLExceptionHelper exceptionHelper) { throw new IllegalArgumentException( "batch key cannot be null" );
if ( key == null || statementLogger == null || exceptionHelper == null ) { }
throw new IllegalArgumentException( "key, statementLogger, and exceptionHelper must be non-null." ); if ( jdbcCoordinator == null ) {
throw new IllegalArgumentException( "JDBC coordinator cannot be null" );
} }
this.key = key; this.key = key;
this.statementLogger = statementLogger; this.jdbcCoordinator = jdbcCoordinator;
this.exceptionHelper = exceptionHelper;
} }
/** /**
@ -74,8 +74,12 @@ public abstract class AbstractBatchImpl implements Batch {
* *
* @return The underlying SQLException helper. * @return The underlying SQLException helper.
*/ */
protected SQLExceptionHelper getSqlExceptionHelper() { protected SQLExceptionHelper sqlExceptionHelper() {
return exceptionHelper; return jdbcCoordinator.getTransactionCoordinator()
.getTransactionContext()
.getTransactionEnvironment()
.getJdbcServices()
.getSqlExceptionHelper();
} }
/** /**
@ -83,8 +87,12 @@ public abstract class AbstractBatchImpl implements Batch {
* *
* @return The underlying JDBC services. * @return The underlying JDBC services.
*/ */
protected SQLStatementLogger getSqlStatementLogger() { protected SQLStatementLogger sqlStatementLogger() {
return statementLogger; return jdbcCoordinator.getTransactionCoordinator()
.getTransactionContext()
.getTransactionEnvironment()
.getJdbcServices()
.getSqlStatementLogger();
} }
/** /**
@ -96,62 +104,49 @@ public abstract class AbstractBatchImpl implements Batch {
return statements; return statements;
} }
/** @Override
* {@inheritDoc} public final BatchKey getKey() {
*/
public final Object getKey() {
return key; return key;
} }
/** @Override
* {@inheritDoc}
*/
public void addObserver(BatchObserver observer) { public void addObserver(BatchObserver observer) {
observers.add( observer ); observers.add( observer );
} }
/** @Override
* {@inheritDoc} public PreparedStatement getBatchStatement(String sql, boolean callable) {
*/
public final PreparedStatement getBatchStatement(Object key, String sql) {
checkConsistentBatchKey( key );
if ( sql == null ) { if ( sql == null ) {
throw new IllegalArgumentException( "sql must be non-null." ); throw new IllegalArgumentException( "sql must be non-null." );
} }
PreparedStatement statement = statements.get( sql ); PreparedStatement statement = statements.get( sql );
if ( statement != null ) { if ( statement == null ) {
log.debug( "reusing prepared statement" ); statement = buildBatchStatement( sql, callable );
statementLogger.logStatement( sql ); statements.put( sql, statement );
} }
else {
log.debug( "reusing batch statement" );
sqlStatementLogger().logStatement( sql );
}
return statement; return statement;
} }
/** private PreparedStatement buildBatchStatement(String sql, boolean callable) {
* {@inheritDoc} try {
*/ if ( callable ) {
// TODO: should this be final??? return jdbcCoordinator.getLogicalConnection().getShareableConnectionProxy().prepareCall( sql );
}
else {
return jdbcCoordinator.getLogicalConnection().getShareableConnectionProxy().prepareStatement( sql );
}
}
catch ( SQLException sqle ) {
log.error( "sqlexception escaped proxy", sqle );
throw sqlExceptionHelper().convert( sqle, "could not prepare batch statement", sql );
}
}
@Override @Override
public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement) {
checkConsistentBatchKey( key );
if ( sql == null ) {
throw new IllegalArgumentException( "sql must be non-null." );
}
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 + "]."
);
}
}
/**
* {@inheritDoc}
*/
public final void execute() { public final void execute() {
notifyObserversExplicitExecution(); notifyObserversExplicitExecution();
if ( statements.isEmpty() ) { if ( statements.isEmpty() ) {
@ -162,7 +157,7 @@ public abstract class AbstractBatchImpl implements Batch {
doExecuteBatch(); doExecuteBatch();
} }
finally { finally {
release(); releaseStatements();
} }
} }
finally { finally {
@ -176,14 +171,16 @@ public abstract class AbstractBatchImpl implements Batch {
statement.close(); statement.close();
} }
catch ( SQLException e ) { catch ( SQLException e ) {
log.error( "unable to release batch statement..." ); log.error( "unable to release batch statement; sqlexception escaped proxy", e );
log.error( "sqlexception escaped proxy", e );
} }
} }
getStatements().clear(); getStatements().clear();
} }
private void notifyObserversExplicitExecution() { /**
* Convenience method to notify registered observers of an explicit execution of this batch.
*/
protected final void notifyObserversExplicitExecution() {
for ( BatchObserver observer : observers ) { for ( BatchObserver observer : observers ) {
observer.batchExplicitlyExecuted(); observer.batchExplicitlyExecuted();
} }
@ -192,12 +189,13 @@ public abstract class AbstractBatchImpl implements Batch {
/** /**
* Convenience method to notify registered observers of an implicit execution of this batch. * Convenience method to notify registered observers of an implicit execution of this batch.
*/ */
protected void notifyObserversImplicitExecution() { protected final void notifyObserversImplicitExecution() {
for ( BatchObserver observer : observers ) { for ( BatchObserver observer : observers ) {
observer.batchImplicitlyExecuted(); observer.batchImplicitlyExecuted();
} }
} }
@Override
public void release() { public void release() {
if ( getStatements() != null && !getStatements().isEmpty() ) { if ( getStatements() != null && !getStatements().isEmpty() ) {
log.info( "On release of batch it still contained JDBC statements" ); log.info( "On release of batch it still contained JDBC statements" );

View File

@ -0,0 +1,89 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.batch.internal;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.jdbc.Expectation;
/**
* @author Steve Ebersole
*/
public class BasicBatchKey implements BatchKey {
private final String comparison;
private final int statementCount;
private final Expectation expectation;
// public BasicBatchKey(String comparison, int statementCount, Expectation expectation) {
// this.comparison = comparison;
// this.statementCount = statementCount;
// this.expectations = new Expectation[statementCount];
// Arrays.fill( this.expectations, expectation );
// }
//
// public BasicBatchKey(String comparison, Expectation... expectations) {
// this.comparison = comparison;
// this.statementCount = expectations.length;
// this.expectations = expectations;
// }
public BasicBatchKey(String comparison, Expectation expectation) {
this.comparison = comparison;
this.statementCount = 1;
this.expectation = expectation;
}
@Override
public Expectation getExpectation() {
return expectation;
}
@Override
public int getBatchedStatementCount() {
return statementCount;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
BasicBatchKey that = (BasicBatchKey) o;
if ( !comparison.equals( that.comparison ) ) {
return false;
}
return true;
}
@Override
public int hashCode() {
return comparison.hashCode();
}
}

View File

@ -23,28 +23,37 @@
*/ */
package org.hibernate.engine.jdbc.batch.internal; package org.hibernate.engine.jdbc.batch.internal;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.spi.Configurable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.hibernate.engine.jdbc.batch.spi.Batch; import java.util.Map;
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. * A builder for {@link Batch} instances.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class BatchBuilder { public class BatchBuilderImpl implements BatchBuilder, Configurable {
private static final Logger log = LoggerFactory.getLogger( BatchBuilder.class ); private static final Logger log = LoggerFactory.getLogger( BatchBuilderImpl.class );
private int size; private int size;
public BatchBuilder() { public BatchBuilderImpl() {
} }
public BatchBuilder(int size) { @Override
public void configure(Map configurationValues) {
size = ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, size );
}
public BatchBuilderImpl(int size) {
this.size = size; this.size = size;
} }
@ -52,13 +61,27 @@ public class BatchBuilder {
this.size = size; this.size = size;
} }
public Batch buildBatch(Object key, @Override
SQLStatementLogger statementLogger, public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) {
SQLExceptionHelper exceptionHelper) {
log.trace( "building batch [size={}]", size ); log.trace( "building batch [size={}]", size );
return size > 1 return size > 1
? new BatchingBatch( key, statementLogger, exceptionHelper, size ) ? new BatchingBatch( key, jdbcCoordinator, size )
: new NonBatchingBatch( key, statementLogger, exceptionHelper ); : new NonBatchingBatch( key, jdbcCoordinator );
}
@Override
public String getManagementDomain() {
return null; // use Hibernate default domain
}
@Override
public String getManagementServiceType() {
return null; // use Hibernate default scheme
}
@Override
public Object getManagementBean() {
return this;
} }
} }

View File

@ -0,0 +1,69 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.batch.internal;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.spi.ServiceException;
import org.hibernate.service.spi.ServiceInitiator;
import org.hibernate.service.spi.ServiceRegistry;
import java.util.Map;
/**
* @author Steve Ebersole
*/
public class BatchBuilderInitiator implements ServiceInitiator<BatchBuilder> {
public static final BatchBuilderInitiator INSTANCE = new BatchBuilderInitiator();
public static final String BUILDER = "hibernate.jdbc.batch.builder";
@Override
public Class<BatchBuilder> getServiceInitiated() {
return BatchBuilder.class;
}
@Override
public BatchBuilder initiateService(Map configurationValues, ServiceRegistry registry) {
final Object builder = configurationValues.get( BUILDER );
if ( builder == null ) {
return new BatchBuilderImpl(
ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, 1 )
);
}
if ( BatchBuilder.class.isInstance( builder ) ) {
return (BatchBuilder) builder;
}
final String builderClassName = builder.toString();
try {
return (BatchBuilder) registry.getService( ClassLoaderService.class ).classForName( builderClassName ).newInstance();
}
catch (Exception e) {
throw new ServiceException( "Could not build explicit BatchBuilder [" + builderClassName + "]", e );
}
}
}

View File

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

View File

@ -23,48 +23,52 @@
*/ */
package org.hibernate.engine.jdbc.batch.internal; package org.hibernate.engine.jdbc.batch.internal;
import java.sql.PreparedStatement; import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import java.sql.SQLException; import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; import java.sql.PreparedStatement;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger; import java.sql.SQLException;
import org.hibernate.jdbc.Expectation; import java.util.Map;
/** /**
* An implementation of {@link org.hibernate.engine.jdbc.batch.spi.Batch} which does not perform batching. It simply executes each statement as it is * An implementation of {@link org.hibernate.engine.jdbc.batch.spi.Batch} which does not perform batching. It simply
* encountered. * executes each statement as it is encountered.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class NonBatchingBatch extends AbstractBatchImpl { public class NonBatchingBatch extends AbstractBatchImpl {
private static final Logger log = LoggerFactory.getLogger( NonBatchingBatch.class ); private static final Logger log = LoggerFactory.getLogger( NonBatchingBatch.class );
protected NonBatchingBatch(Object key, protected NonBatchingBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) {
SQLStatementLogger statementLogger, super( key, jdbcCoordinator );
SQLExceptionHelper exceptionHelper) {
super( key, statementLogger, exceptionHelper );
} }
public void addToBatch(Object key, String sql, Expectation expectation) { @Override
checkConsistentBatchKey( key ); public void addToBatch() {
if ( sql == null ) {
throw new IllegalArgumentException( "sql must be non-null." );
}
notifyObserversImplicitExecution(); notifyObserversImplicitExecution();
try { for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
final PreparedStatement statement = getStatements().get( sql ); try {
final int rowCount = statement.executeUpdate(); final PreparedStatement statement = entry.getValue();
expectation.verifyOutcome( rowCount, statement, 0 ); final int rowCount = statement.executeUpdate();
} getKey().getExpectation().verifyOutcome( rowCount, statement, 0 );
catch ( SQLException e ) { try {
log.error( "sqlexception escaped proxy", e ); statement.close();
throw getSqlExceptionHelper().convert( e, "could not execute batch statement", sql ); }
catch (SQLException e) {
log.debug( "Unable to close non-batched batch statement", e );
}
}
catch ( SQLException e ) {
log.debug( "sqlexception escaped proxy", e );
throw sqlExceptionHelper().convert( e, "could not execute batch statement", entry.getKey() );
}
} }
getStatements().clear();
} }
@Override
protected void doExecuteBatch() { protected void doExecuteBatch() {
// nothing to do // nothing to do
} }

View File

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

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.batch.spi;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.service.spi.Manageable;
import org.hibernate.service.spi.Service;
/**
* A builder for {@link Batch} instances
*
* @author Steve Ebersole
*/
public interface BatchBuilder extends Service, Manageable {
/**
* Build a batch.
*
* @param key Value to uniquely identify a batch
* @param jdbcCoordinator The JDBC coordinator with which to coordinate efforts
*
* @return The built batch
*/
public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator);
}

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,29 +20,30 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.transaction; package org.hibernate.engine.jdbc.batch.spi;
import org.hibernate.jdbc.Expectation;
/** /**
* {@link TransactionManagerLookup} strategy for Resin * Unique key for batch identification.
* *
* @author Aapo Laakkonen * @author Steve Ebersole
*/ */
public class ResinTransactionManagerLookup extends JNDITransactionManagerLookup { public interface BatchKey {
/**
* How many statements will be in this batch?
* <p/>
* Note that this is distinctly different than the size of the batch.
*
* @return The number of statements.
*/
public int getBatchedStatementCount();
/** /**
* {@inheritDoc} * Get the expectation pertaining to the outcome of the {@link Batch} associated with this key.
*
* @return The expectations
*/ */
protected String getName() { public Expectation getExpectation();
return "java:comp/TransactionManager";
}
/**
* {@inheritDoc}
*/
public String getUserTransactionName() {
return "java:comp/UserTransaction";
}
} }

View File

@ -1,611 +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.engine.jdbc.internal;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.ScrollMode;
import org.hibernate.engine.SessionFactoryImplementor;
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.Expectation;
/**
* Encapsulates JDBC Connection management logic needed by Hibernate.
* <p/>
* The lifecycle is intended to span a logical series of interactions with the
* database. Internally, this means the the lifecycle of the Session.
*
* @author Steve Ebersole
*/
public class ConnectionManagerImpl implements ConnectionManager {
private static final Logger log = LoggerFactory.getLogger( ConnectionManagerImpl.class );
public static interface Callback extends ConnectionObserver {
public boolean isTransactionInProgress();
}
// TODO: check if it's ok to change the method names in Callback
private transient Interceptor interceptor;
private final Callback callback;
private transient LogicalConnectionImpl logicalConnection;
private transient StatementPreparer statementPreparer;
private final transient BatchBuilder batchBuilder;
private Batch batch;
/**
* Constructs a ConnectionManager.
* <p/>
* This is the form used internally.
*
* @param callback An observer for internal state change.
* @param releaseMode The mode by which to release JDBC connections.
* @param suppliedConnection An externally supplied connection.
*/
public ConnectionManagerImpl(
SessionFactoryImplementor factory,
Callback callback,
ConnectionReleaseMode releaseMode,
Connection suppliedConnection,
Interceptor interceptor) {
this( factory,
callback,
interceptor,
new LogicalConnectionImpl(
suppliedConnection,
releaseMode,
factory.getJdbcServices(),
factory.getStatistics() != null ? factory.getStatisticsImplementor() : null
)
);
}
/**
* Private constructor used exclusively from custom serialization
*/
private ConnectionManagerImpl(
SessionFactoryImplementor factory,
Callback callback,
Interceptor interceptor,
LogicalConnectionImpl logicalConnection
) {
this.callback = callback;
this.interceptor = interceptor;
this.logicalConnection = logicalConnection;
this.logicalConnection.addObserver( callback );
this.statementPreparer = new StatementPreparer( logicalConnection, factory.getSettings() );
this.batchBuilder = factory.getSettings().getBatchBuilder();
}
/**
* Retrieves the connection currently managed by this ConnectionManager.
* <p/>
* Note, that we may need to obtain a connection to return here if a
* connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
* or has previously been aggressively released (if supported in this environment).
*
* @return The current Connection.
*
* @throws HibernateException Indicates a connection is currently not
* available (we are currently manually disconnected).
*/
@Override
public Connection getConnection() throws HibernateException {
return logicalConnection.getConnection();
}
@Override
public boolean hasBorrowedConnection() {
// used from testsuite
return logicalConnection.hasBorrowedConnection();
}
public Connection borrowConnection() {
return logicalConnection.borrowConnection();
}
@Override
public void releaseBorrowedConnection() {
logicalConnection.releaseBorrowedConnection();
}
/**
* Is the connection considered "auto-commit"?
*
* @return True if we either do not have a connection, or the connection
* really is in auto-commit mode.
*
* @throws SQLException Can be thrown by the Connection.isAutoCommit() check.
*/
public boolean isAutoCommit() throws SQLException {
return logicalConnection == null ||
! logicalConnection.isOpen() ||
! logicalConnection.isPhysicallyConnected() ||
logicalConnection.getConnection().getAutoCommit();
}
/**
* Will connections be released after each statement execution?
* <p/>
* Connections will be released after each statement if either:<ul>
* <li>the defined release-mode is {@link ConnectionReleaseMode#AFTER_STATEMENT}; or
* <li>the defined release-mode is {@link ConnectionReleaseMode#AFTER_TRANSACTION} but
* we are in auto-commit mode.
* <p/>
* release-mode = {@link ConnectionReleaseMode#ON_CLOSE} should [b]never[/b] release
* a connection.
*
* @return True if the connections will be released after each statement; false otherwise.
*/
public boolean isAggressiveRelease() {
if ( logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_STATEMENT ) {
return true;
}
else if ( logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION ) {
boolean inAutoCommitState;
try {
inAutoCommitState = isAutoCommit() && ! callback.isTransactionInProgress();
}
catch( SQLException e ) {
// assume we are in an auto-commit state
inAutoCommitState = true;
}
return inAutoCommitState;
}
return false;
}
/**
* Modified version of {@link #isAggressiveRelease} which does not force a
* transaction check. This is solely used from our {@link #afterTransaction}
* callback, so no need to do the check; plus it seems to cause problems on
* websphere (god i love websphere ;)
* </p>
* It uses this information to decide if an aggressive release was skipped
* do to open resources, and if so forces a release.
*
* @return True if the connections will be released after each statement; false otherwise.
*/
private boolean isAggressiveReleaseNoTransactionCheck() {
if ( logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_STATEMENT ) {
return true;
}
else {
boolean inAutoCommitState;
try {
inAutoCommitState = isAutoCommit();
}
catch( SQLException e ) {
// assume we are in an auto-commit state
inAutoCommitState = true;
}
return logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION && inAutoCommitState;
}
}
/**
* Is this ConnectionManager instance "logically" connected. Meaning
* do we either have a cached connection available or do we have the
* ability to obtain a connection on demand.
*
* @return True if logically connected; false otherwise.
*/
@Override
public boolean isCurrentlyConnected() {
return logicalConnection != null && logicalConnection.isLogicallyConnected();
}
/**
* To be called after execution of each JDBC statement. Used to
* conditionally release the JDBC connection aggressively if
* the configured release mode indicates.
*/
@Override
public void afterStatement() {
if ( isAggressiveRelease() ) {
logicalConnection.afterStatementExecution();
}
}
/**
* To be called after local transaction completion. Used to conditionally
* release the JDBC connection aggressively if the configured release mode
* indicates.
*/
public void afterTransaction() {
if ( logicalConnection != null ) {
if ( isAfterTransactionRelease() || isAggressiveReleaseNoTransactionCheck() ) {
logicalConnection.afterTransaction();
}
else if ( isOnCloseRelease() ) {
// log a message about potential connection leaks
log.debug( "transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!" );
}
}
if ( statementPreparer != null ) {
statementPreparer.unsetTransactionTimeout();
}
}
private boolean isAfterTransactionRelease() {
return logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION;
}
private boolean isOnCloseRelease() {
return logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.ON_CLOSE;
}
private boolean isLogicallyConnected() {
return logicalConnection != null && logicalConnection.isOpen();
}
@Override
public void setTransactionTimeout(int seconds) {
statementPreparer.setTransactionTimeout( seconds );
}
/**
* To be called after Session completion. Used to release the JDBC
* connection.
*
* @return The connection mantained here at time of close. Null if
* there was no connection cached internally.
*/
@Override
public Connection close() {
return cleanup();
}
/**
* Manually disconnect the underlying JDBC Connection. The assumption here
* is that the manager will be reconnected at a later point in time.
*
* @return The connection mantained here at time of disconnect. Null if
* there was no connection cached internally.
*/
@Override
public Connection manualDisconnect() {
if ( ! isLogicallyConnected() ) {
throw new IllegalStateException( "cannot manually disconnect because not logically connected." );
}
releaseBatch();
return logicalConnection.manualDisconnect();
}
/**
* Manually reconnect the underlying JDBC Connection. Should be called at
* some point after manualDisconnect().
* <p/>
* This form is used for ConnectionProvider-supplied connections.
*/
@Override
public void manualReconnect() {
manualReconnect( null );
}
/**
* Manually reconnect the underlying JDBC Connection. Should be called at
* some point after manualDisconnect().
* <p/>
* This form is used for user-supplied connections.
*/
@Override
public void manualReconnect(Connection suppliedConnection) {
if ( ! isLogicallyConnected() ) {
throw new IllegalStateException( "cannot manually disconnect because not logically connected." );
}
logicalConnection.reconnect( suppliedConnection );
}
/**
* Releases the Connection and cleans up any resources associated with
* that Connection. This is intended for use:
* 1) at the end of the session
* 2) on a manual disconnect of the session
* 3) from afterTransaction(), in the case of skipped aggressive releasing
*
* @return The released connection.
* @throws HibernateException
*/
private Connection cleanup() throws HibernateException {
if ( logicalConnection == null ) {
log.trace( "connection already null in cleanup : no action");
return null;
}
try {
log.trace( "performing cleanup" );
releaseBatch();
statementPreparer.close();
Connection c = logicalConnection.close();
return c;
}
finally {
batch = null;
statementPreparer = null;
logicalConnection = null;
}
}
/**
* Callback to let us know that a flush is beginning. We use this fact
* to temporarily circumvent aggressive connection releasing until after
* the flush cycle is complete {@link #flushEnding()}
*/
@Override
public void flushBeginning() {
log.trace( "registering flush begin" );
logicalConnection.disableReleases();
}
/**
* Callback to let us know that a flush is ending. We use this fact to
* stop circumventing aggressive releasing connections.
*/
@Override
public void flushEnding() {
log.trace( "registering flush end" );
logicalConnection.enableReleases();
afterStatement();
}
/**
* 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 {
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) {
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 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) {
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( statementPreparer.prepareStatement( getSQL( sql ), true ) );
}
/**
* Get a batchable prepared statement to use for inserting / deleting / updating
* (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.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.
*/
@Override
public PreparedStatement prepareBatchStatement(Object key, String sql, boolean isCallable) {
if ( key == null ) {
throw new IllegalArgumentException( "batch key must be non-null." );
}
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;
}
/**
* 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) {
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();
}
@Override
public void addToBatch(Object batchKey, String sql, Expectation expectation) {
batch.addToBatch( batchKey, sql, expectation );
}
@Override
public void executeBatch() throws HibernateException {
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) {
sql = interceptor.onPrepareStatement( sql );
if ( sql==null || sql.length() == 0 ) {
throw new AssertionFailure( "Interceptor.onPrepareStatement() returned null or empty string." );
}
return sql;
}
public boolean isReadyForSerialization() {
return logicalConnection == null ? true : logicalConnection.isReadyForSerialization();
}
/**
* Used during serialization.
*
* @param oos The stream to which we are being written.
* @throws IOException Indicates an I/O error writing to the stream
*/
private void writeObject(ObjectOutputStream oos) throws IOException {
if ( !isReadyForSerialization() ) {
throw new IllegalStateException( "Cannot serialize a ConnectionManager while connected" );
}
oos.defaultWriteObject();
}
/**
* Used during deserialization.
*
* @param ois The stream from which we are being read.
* @throws IOException Indicates an I/O error reading the stream
* @throws ClassNotFoundException Indicates resource class resolution.
*/
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
}
public void serialize(ObjectOutputStream oos) throws IOException {
logicalConnection.serialize( oos );
}
public static ConnectionManagerImpl deserialize(
ObjectInputStream ois,
SessionFactoryImplementor factory,
Interceptor interceptor,
ConnectionReleaseMode connectionReleaseMode,
Callback callback) throws IOException {
return new ConnectionManagerImpl(
factory,
callback,
interceptor,
LogicalConnectionImpl.deserialize(
ois,
factory.getJdbcServices(),
factory.getStatistics() != null ? factory.getStatisticsImplementor() : null,
connectionReleaseMode
)
);
}
}

View File

@ -1,369 +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.engine.jdbc.internal;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import javax.transaction.TransactionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.SessionException;
import org.hibernate.Transaction;
import org.hibernate.TransactionException;
import org.hibernate.engine.jdbc.spi.ConnectionManager;
import org.hibernate.engine.jdbc.spi.JDBCContext;
import org.hibernate.transaction.synchronization.CallbackCoordinator;
import org.hibernate.transaction.synchronization.HibernateSynchronizationImpl;
import org.hibernate.util.JTAHelper;
import org.hibernate.engine.SessionFactoryImplementor;
/**
* Acts as the mediary between "entity-mode related" sessions in terms of
* their interaction with the JDBC data store.
*
* @author Steve Ebersole
*/
public class JDBCContextImpl implements ConnectionManagerImpl.Callback, JDBCContext {
// TODO : make this the factory for "entity mode related" sessions;
// also means making this the target of transaction-synch and the
// thing that knows how to cascade things between related sessions
//
// At that point, perhaps this thing is a "SessionContext", and
// ConnectionManager is a "JDBCContext"? A "SessionContext" should
// live in the impl package...
private static final Logger log = LoggerFactory.getLogger( JDBCContextImpl.class );
private Context owner;
private ConnectionManagerImpl connectionManager;
private transient boolean isTransactionCallbackRegistered;
private transient Transaction hibernateTransaction;
private CallbackCoordinator jtaSynchronizationCallbackCoordinator;
public JDBCContextImpl(Context owner, Connection connection, Interceptor interceptor) {
this.owner = owner;
this.connectionManager = new ConnectionManagerImpl(
owner.getFactory(),
this,
owner.getConnectionReleaseMode(),
connection,
interceptor
);
final boolean registerSynchronization = owner.isAutoCloseSessionEnabled()
|| owner.isFlushBeforeCompletionEnabled()
|| owner.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION;
if ( registerSynchronization ) {
registerSynchronizationIfPossible();
}
}
/**
* Private constructor used exclusively for custom serialization...
*
*/
private JDBCContextImpl() {
}
@Override
public CallbackCoordinator getJtaSynchronizationCallbackCoordinator() {
return jtaSynchronizationCallbackCoordinator;
}
private CallbackCoordinator getJtaSynchronizationCallbackCoordinator(javax.transaction.Transaction jtaTransaction) {
jtaSynchronizationCallbackCoordinator = new CallbackCoordinator( owner, this, jtaTransaction, hibernateTransaction );
return jtaSynchronizationCallbackCoordinator;
}
@Override
public void cleanUpJtaSynchronizationCallbackCoordinator() {
jtaSynchronizationCallbackCoordinator = null;
}
// ConnectionManager.Callback implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public void physicalConnectionObtained(Connection connection) {
if ( owner.getFactory().getStatistics().isStatisticsEnabled() ) {
owner.getFactory().getStatisticsImplementor().connect();
}
}
@Override
public void physicalConnectionReleased() {
if ( !isTransactionCallbackRegistered ) {
afterTransactionCompletion( false, null );
// Note : success = false, because we don't know the outcome of the transaction
}
}
@Override
public void logicalConnectionClosed() {
// TODO: anything need to be done?
}
@Override
public SessionFactoryImplementor getFactory() {
return owner.getFactory();
}
@Override
public ConnectionManager getConnectionManager() {
return connectionManager;
}
public Connection borrowConnection() {
return connectionManager.borrowConnection();
}
@Override
public Connection connection() throws HibernateException {
if ( owner.isClosed() ) {
throw new SessionException( "Session is closed" );
}
return connectionManager.getConnection();
}
@Override
public boolean registerCallbackIfNecessary() {
if ( isTransactionCallbackRegistered ) {
return false;
}
else {
isTransactionCallbackRegistered = true;
return true;
}
}
@Override
public boolean registerSynchronizationIfPossible() {
if ( isTransactionCallbackRegistered ) {
// we already have a callback registered; either a local
// (org.hibernate.Transaction) transaction has accepted
// callback responsibilities, or we have previously
// registered a transaction synch.
return true;
}
boolean localCallbacksOnly = owner.getFactory().getSettings()
.getTransactionFactory()
.areCallbacksLocalToHibernateTransactions();
if ( localCallbacksOnly ) {
// the configured transaction-factory says it only supports
// local callback mode, so no sense attempting to register a
// JTA Synchronization
return false;
}
TransactionManager tm = owner.getFactory().getTransactionManager();
if ( tm == null ) {
// if there is no TM configured, we will not be able to access
// the javax.transaction.Transaction object in order to
// register a synch anyway.
return false;
}
else {
try {
if ( !isTransactionInProgress() ) {
log.trace( "TransactionFactory reported no active transaction; Synchronization not registered" );
return false;
}
else {
javax.transaction.Transaction tx = tm.getTransaction();
if ( JTAHelper.isMarkedForRollback( tx ) ) {
// transactions marked for rollback-only cause some TM impls to throw exceptions
log.debug( "Transaction is marked for rollback; skipping Synchronization registration" );
return false;
}
else {
if ( hibernateTransaction == null ) {
hibernateTransaction = owner.getFactory().getSettings().getTransactionFactory().createTransaction( this, owner );
}
tx.registerSynchronization(
new HibernateSynchronizationImpl( getJtaSynchronizationCallbackCoordinator( tx ) )
);
// tx.registerSynchronization( new CacheSynchronization(owner, this, tx, hibernateTransaction) );
isTransactionCallbackRegistered = true;
log.debug("successfully registered Synchronization");
return true;
}
}
}
catch( HibernateException e ) {
throw e;
}
catch (Exception e) {
throw new TransactionException( "could not register synchronization with JTA TransactionManager", e );
}
}
}
@Override
public boolean isTransactionInProgress() {
return owner.getFactory().getSettings().getTransactionFactory()
.isTransactionInProgress( this, owner, hibernateTransaction );
}
@Override
public Transaction getTransaction() throws HibernateException {
if (hibernateTransaction==null) {
hibernateTransaction = owner.getFactory().getSettings()
.getTransactionFactory()
.createTransaction( this, owner );
}
return hibernateTransaction;
}
@Override
public void beforeTransactionCompletion(Transaction tx) {
log.trace( "before transaction completion" );
owner.beforeTransactionCompletion(tx);
}
/**
* We cannot rely upon this method being called! It is only
* called if we are using Hibernate Transaction API.
*/
@Override
public void afterTransactionBegin(Transaction tx) {
log.trace( "after transaction begin" );
owner.afterTransactionBegin(tx);
}
@Override
public void afterTransactionCompletion(boolean success, Transaction tx) {
log.trace( "after transaction completion" );
if ( getFactory().getStatistics().isStatisticsEnabled() ) {
getFactory().getStatisticsImplementor().endTransaction(success);
}
connectionManager.afterTransaction();
isTransactionCallbackRegistered = false;
hibernateTransaction = null;
owner.afterTransactionCompletion(success, tx);
}
/**
* Called after executing a query outside the scope of
* a Hibernate or JTA transaction
*/
@Override
public void afterNontransactionalQuery(boolean success) {
log.trace( "after autocommit" );
try {
// check to see if the connection is in auto-commit
// mode (no connection means aggressive connection
// release outside a JTA transaction context, so MUST
// be autocommit mode)
boolean isAutocommit = connectionManager.isAutoCommit();
connectionManager.afterTransaction();
if ( isAutocommit ) {
owner.afterTransactionCompletion(success, null);
}
}
catch (SQLException sqle) {
throw owner.getFactory().getSQLExceptionHelper().convert(
sqle,
"could not inspect JDBC autocommit mode"
);
}
}
// serialization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public boolean isReadyForSerialization() {
return connectionManager.isReadyForSerialization();
}
private void writeObject(ObjectOutputStream oos) throws IOException {
// isTransactionCallbackRegistered denotes whether any Hibernate
// Transaction has registered as a callback against this
// JDBCContext; only one such callback is allowed. Directly
// serializing this value causes problems with JDBCTransaction,
// or really any Transaction impl where the callback is local
// to the Transaction instance itself, since that Transaction
// is not serialized along with the JDBCContext. Thus we
// handle that fact here explicitly...
oos.defaultWriteObject();
boolean deserHasCallbackRegistered = isTransactionCallbackRegistered
&& ! owner.getFactory().getSettings().getTransactionFactory()
.areCallbacksLocalToHibernateTransactions();
oos.writeBoolean( deserHasCallbackRegistered );
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
isTransactionCallbackRegistered = ois.readBoolean();
}
/**
* Custom serialization routine used during serialization of a
* Session/PersistenceContext for increased performance.
*
* @param oos The stream to which we should write the serial data.
* @throws IOException
*/
public void serialize(ObjectOutputStream oos) throws IOException {
connectionManager.serialize( oos );
}
/**
* Custom deserialization routine used during deserialization of a
* Session/PersistenceContext for increased performance.
*
* @param ois The stream from which to read the entry.
* @throws IOException
*/
public static JDBCContextImpl deserialize(
ObjectInputStream ois,
Context context,
Interceptor interceptor) throws IOException, ClassNotFoundException {
JDBCContextImpl jdbcContext = new JDBCContextImpl();
jdbcContext.owner = context;
jdbcContext.connectionManager = ConnectionManagerImpl.deserialize(
ois,
context.getFactory(),
interceptor,
context.getConnectionReleaseMode(),
jdbcContext
);
return jdbcContext;
}
}

View File

@ -0,0 +1,236 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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 org.hibernate.HibernateException;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.StatementPreparer;
import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
import org.hibernate.jdbc.Work;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Standard Hibernate implementation of {@link JdbcCoordinator}
* <p/>
* IMPL NOTE : Custom serialization handling!
*
* @author Steve Ebersole
*/
public class JdbcCoordinatorImpl implements JdbcCoordinator {
private static final Logger log = LoggerFactory.getLogger( JdbcCoordinatorImpl.class );
private transient TransactionCoordinatorImpl transactionCoordinator;
private final transient LogicalConnectionImpl logicalConnection;
private transient Batch currentBatch;
public JdbcCoordinatorImpl(
Connection userSuppliedConnection,
TransactionCoordinatorImpl transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator;
this.logicalConnection = new LogicalConnectionImpl(
userSuppliedConnection,
transactionCoordinator.getTransactionContext().getConnectionReleaseMode(),
transactionCoordinator.getTransactionContext().getTransactionEnvironment().getJdbcServices()
);
}
private JdbcCoordinatorImpl(LogicalConnectionImpl logicalConnection) {
this.logicalConnection = logicalConnection;
}
@Override
public TransactionCoordinator getTransactionCoordinator() {
return transactionCoordinator;
}
@Override
public LogicalConnectionImplementor getLogicalConnection() {
return logicalConnection;
}
protected TransactionEnvironment transactionEnvironment() {
return getTransactionCoordinator().getTransactionContext().getTransactionEnvironment();
}
protected SessionFactoryImplementor sessionFactory() {
return transactionEnvironment().getSessionFactory();
}
protected BatchBuilder batchBuilder() {
return sessionFactory().getServiceRegistry().getService( BatchBuilder.class );
}
private SQLExceptionHelper sqlExceptionHelper() {
return transactionEnvironment().getJdbcServices().getSqlExceptionHelper();
}
private int flushDepth = 0;
@Override
public void flushBeginning() {
if ( flushDepth == 0 ) {
logicalConnection.disableReleases();
}
flushDepth++;
}
@Override
public void flushEnding() {
flushDepth--;
if ( flushDepth < 0 ) {
throw new HibernateException( "Mismatched flush handling" );
}
if ( flushDepth == 0 ) {
logicalConnection.enableReleases();
}
}
@Override
public Connection close() {
if ( currentBatch != null ) {
log.warn( "Closing un-released batch" );
currentBatch.release();
}
return logicalConnection.close();
}
@Override
public Batch getBatch(BatchKey key) {
if ( currentBatch != null ) {
if ( currentBatch.getKey().equals( key ) ) {
return currentBatch;
}
else {
currentBatch.execute();
currentBatch.release();
}
}
currentBatch = batchBuilder().buildBatch( key, this );
return currentBatch;
}
@Override
public void abortBatch() {
if ( currentBatch != null ) {
currentBatch.release();
}
}
private transient StatementPreparer statementPreparer;
@Override
public StatementPreparer getStatementPreparer() {
if ( statementPreparer == null ) {
statementPreparer = new StatementPreparerImpl( this );
}
return statementPreparer;
}
@Override
public void setTransactionTimeOut(int timeOut) {
getStatementPreparer().setTransactionTimeOut( timeOut );
}
/**
* To be called after local transaction completion. Used to conditionally
* release the JDBC connection aggressively if the configured release mode
* indicates.
*/
public void afterTransaction() {
logicalConnection.afterTransaction();
if ( statementPreparer != null ) {
statementPreparer.unsetTransactionTimeOut();
}
}
public void coordinateWork(Work work) {
Connection connection = getLogicalConnection().getDistinctConnectionProxy();
try {
work.execute( connection );
getLogicalConnection().afterStatementExecution();
}
catch ( SQLException e ) {
throw sqlExceptionHelper().convert( e, "error executing work" );
}
finally {
try {
if ( ! connection.isClosed() ) {
connection.close();
}
}
catch (SQLException e) {
log.debug( "Error closing connection proxy", e );
}
}
}
public void executeBatch() {
if ( currentBatch != null ) {
currentBatch.execute();
currentBatch.release(); // needed?
}
}
@Override
public void cancelLastQuery() {
logicalConnection.getResourceRegistry().cancelLastQuery();
}
public void serialize(ObjectOutputStream oos) throws IOException {
if ( ! logicalConnection.isReadyForSerialization() ) {
throw new HibernateException( "Cannot serialize Session while connected" );
}
logicalConnection.serialize( oos );
}
public static JdbcCoordinatorImpl deserialize(
ObjectInputStream ois,
TransactionContext transactionContext) throws IOException, ClassNotFoundException {
return new JdbcCoordinatorImpl( LogicalConnectionImpl.deserialize( ois, transactionContext ) );
}
public void afterDeserialize(TransactionCoordinatorImpl transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator;
}
}

View File

@ -23,43 +23,46 @@
*/ */
package org.hibernate.engine.jdbc.internal; package org.hibernate.engine.jdbc.internal;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.spi.NonDurableConnectionObserver;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.util.CollectionHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
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.BorrowedConnectionProxy;
import org.hibernate.stat.StatisticsImplementor;
/** /**
* LogicalConnectionImpl implementation * Standard Hibernate {@link org.hibernate.engine.jdbc.spi.LogicalConnection} implementation
* <p/>
* IMPL NOTE : Custom serialization handling!
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class LogicalConnectionImpl implements LogicalConnectionImplementor { public class LogicalConnectionImpl implements LogicalConnectionImplementor {
private static final Logger log = LoggerFactory.getLogger( LogicalConnectionImpl.class ); private static final Logger log = LoggerFactory.getLogger( LogicalConnectionImpl.class );
private Connection physicalConnection; private transient Connection physicalConnection;
private Connection borrowedConnection; private transient Connection shareableConnectionProxy;
private final ConnectionReleaseMode connectionReleaseMode; private final transient ConnectionReleaseMode connectionReleaseMode;
private final JdbcServices jdbcServices; private final transient JdbcServices jdbcServices;
private final StatisticsImplementor statisticsImplementor; private final transient JdbcResourceRegistry jdbcResourceRegistry;
private final JdbcResourceRegistry jdbcResourceRegistry; private final transient List<ConnectionObserver> observers;
private final List<ConnectionObserver> observers = new ArrayList<ConnectionObserver>();
private boolean releasesEnabled = true; private boolean releasesEnabled = true;
@ -67,40 +70,41 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
private boolean isClosed; private boolean isClosed;
public LogicalConnectionImpl(Connection userSuppliedConnection, public LogicalConnectionImpl(
ConnectionReleaseMode connectionReleaseMode, Connection userSuppliedConnection,
JdbcServices jdbcServices, ConnectionReleaseMode connectionReleaseMode,
StatisticsImplementor statisticsImplementor JdbcServices jdbcServices) {
) { this(
this( connectionReleaseMode, connectionReleaseMode,
jdbcServices, jdbcServices,
statisticsImplementor, (userSuppliedConnection != null),
userSuppliedConnection != null, false,
false new ArrayList<ConnectionObserver>()
); );
this.physicalConnection = userSuppliedConnection; this.physicalConnection = userSuppliedConnection;
} }
private LogicalConnectionImpl(ConnectionReleaseMode connectionReleaseMode, private LogicalConnectionImpl(
JdbcServices jdbcServices, ConnectionReleaseMode connectionReleaseMode,
StatisticsImplementor statisticsImplementor, JdbcServices jdbcServices,
boolean isUserSuppliedConnection, boolean isUserSuppliedConnection,
boolean isClosed) { boolean isClosed,
List<ConnectionObserver> observers) {
this.connectionReleaseMode = determineConnectionReleaseMode( this.connectionReleaseMode = determineConnectionReleaseMode(
jdbcServices, isUserSuppliedConnection, connectionReleaseMode jdbcServices, isUserSuppliedConnection, connectionReleaseMode
); );
this.jdbcServices = jdbcServices; this.jdbcServices = jdbcServices;
this.statisticsImplementor = statisticsImplementor; this.jdbcResourceRegistry = new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() );
this.jdbcResourceRegistry = this.observers = observers;
new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() );
this.isUserSuppliedConnection = isUserSuppliedConnection; this.isUserSuppliedConnection = isUserSuppliedConnection;
this.isClosed = isClosed; this.isClosed = isClosed;
} }
private static ConnectionReleaseMode determineConnectionReleaseMode(JdbcServices jdbcServices, private static ConnectionReleaseMode determineConnectionReleaseMode(
boolean isUserSuppliedConnection, JdbcServices jdbcServices,
ConnectionReleaseMode connectionReleaseMode) { boolean isUserSuppliedConnection,
ConnectionReleaseMode connectionReleaseMode) {
if ( isUserSuppliedConnection ) { if ( isUserSuppliedConnection ) {
return ConnectionReleaseMode.ON_CLOSE; return ConnectionReleaseMode.ON_CLOSE;
} }
@ -114,60 +118,37 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
} }
} }
/** @Override
* {@inheritDoc}
*/
public JdbcServices getJdbcServices() { public JdbcServices getJdbcServices() {
return jdbcServices; return jdbcServices;
} }
/** @Override
* {@inheritDoc}
*/
public StatisticsImplementor getStatisticsImplementor() {
return statisticsImplementor;
}
/**
* {@inheritDoc}
*/
public JdbcResourceRegistry getResourceRegistry() { public JdbcResourceRegistry getResourceRegistry() {
return jdbcResourceRegistry; return jdbcResourceRegistry;
} }
/** @Override
* {@inheritDoc}
*/
public void addObserver(ConnectionObserver observer) { public void addObserver(ConnectionObserver observer) {
observers.add( observer ); observers.add( observer );
} }
/** @Override
* {@inheritDoc} public void removeObserver(ConnectionObserver connectionObserver) {
*/ observers.remove( connectionObserver );
}
@Override
public boolean isOpen() { public boolean isOpen() {
return !isClosed; return !isClosed;
} }
/** @Override
* {@inheritDoc}
*/
public boolean isLogicallyConnected() {
return isUserSuppliedConnection ?
isPhysicallyConnected() :
isOpen();
}
/**
* {@inheritDoc}
*/
public boolean isPhysicallyConnected() { public boolean isPhysicallyConnected() {
return physicalConnection != null; return physicalConnection != null;
} }
/** @Override
* {@inheritDoc}
*/
public Connection getConnection() throws HibernateException { public Connection getConnection() throws HibernateException {
if ( isClosed ) { if ( isClosed ) {
throw new HibernateException( "Logical connection is closed" ); throw new HibernateException( "Logical connection is closed" );
@ -182,16 +163,33 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
return physicalConnection; return physicalConnection;
} }
@Override
public Connection getShareableConnectionProxy() {
if ( shareableConnectionProxy == null ) {
shareableConnectionProxy = buildConnectionProxy();
}
return shareableConnectionProxy;
}
private Connection buildConnectionProxy() {
return ProxyBuilder.buildConnection( this );
}
@Override
public Connection getDistinctConnectionProxy() {
return buildConnectionProxy();
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public Connection close() { public Connection close() {
Connection c = physicalConnection; log.trace( "closing logical connection" );
Connection c = isUserSuppliedConnection ? physicalConnection : null;
try { try {
releaseBorrowedConnection(); releaseProxies();
log.trace( "closing logical connection" ); jdbcResourceRegistry.close();
if ( !isUserSuppliedConnection && physicalConnection != null ) { if ( !isUserSuppliedConnection && physicalConnection != null ) {
jdbcResourceRegistry.close();
releaseConnection(); releaseConnection();
} }
return c; return c;
@ -204,46 +202,28 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
for ( ConnectionObserver observer : observers ) { for ( ConnectionObserver observer : observers ) {
observer.logicalConnectionClosed(); observer.logicalConnectionClosed();
} }
observers.clear();
} }
} }
/** private void releaseProxies() {
* {@inheritDoc} if ( shareableConnectionProxy != null ) {
*/ try {
shareableConnectionProxy.close();
}
catch (SQLException e) {
log.debug( "Error releasing shared connection proxy", e );
}
}
shareableConnectionProxy = null;
}
@Override
public ConnectionReleaseMode getConnectionReleaseMode() { public ConnectionReleaseMode getConnectionReleaseMode() {
return connectionReleaseMode; return connectionReleaseMode;
} }
public boolean hasBorrowedConnection() { @Override
return borrowedConnection != null;
}
public Connection borrowConnection() {
if ( isClosed ) {
throw new HibernateException( "connection has been closed" );
}
if ( isUserSuppliedConnection ) {
return physicalConnection;
}
else {
if ( borrowedConnection == null ) {
borrowedConnection = BorrowedConnectionProxy.generateProxy( this );
}
return borrowedConnection;
}
}
public void releaseBorrowedConnection() {
if ( borrowedConnection != null ) {
try {
BorrowedConnectionProxy.renderUnuseable( borrowedConnection );
}
finally {
borrowedConnection = null;
}
}
}
public void afterStatementExecution() { public void afterStatementExecution() {
log.trace( "starting after statement execution processing [{}]", connectionReleaseMode ); log.trace( "starting after statement execution processing [{}]", connectionReleaseMode );
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) { if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
@ -255,13 +235,11 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
log.debug( "skipping aggressive release due to registered resources" ); log.debug( "skipping aggressive release due to registered resources" );
return; return;
} }
else if ( borrowedConnection != null ) {
log.debug( "skipping aggresive-release due to borrowed connection" );
}
releaseConnection(); releaseConnection();
} }
} }
@Override
public void afterTransaction() { public void afterTransaction() {
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT || if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ||
connectionReleaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) { connectionReleaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
@ -273,20 +251,21 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
} }
} }
@Override
public void disableReleases() { public void disableReleases() {
log.trace( "disabling releases" ); log.trace( "disabling releases" );
releasesEnabled = false; releasesEnabled = false;
} }
@Override
public void enableReleases() { public void enableReleases() {
log.trace( "(re)enabling releases" ); log.trace( "(re)enabling releases" );
releasesEnabled = true; releasesEnabled = true;
//FIXME: uncomment after new batch stuff is integrated!!! afterStatementExecution();
//afterStatementExecution();
} }
/** /**
* Force aggresive release of the underlying connection. * Force aggressive release of the underlying connection.
*/ */
public void aggressiveRelease() { public void aggressiveRelease() {
if ( isUserSuppliedConnection ) { if ( isUserSuppliedConnection ) {
@ -302,7 +281,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
/** /**
* Pysically opens a JDBC Connection. * Physically opens a JDBC Connection.
* *
* @throws org.hibernate.JDBCException Indicates problem opening a connection * @throws org.hibernate.JDBCException Indicates problem opening a connection
*/ */
@ -349,32 +328,32 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
for ( ConnectionObserver observer : observers ) { for ( ConnectionObserver observer : observers ) {
observer.physicalConnectionReleased(); observer.physicalConnectionReleased();
} }
releaseNonDurableObservers();
} }
/** @Override
* Manually disconnect the underlying JDBC Connection. The assumption here
* is that the manager will be reconnected at a later point in time.
*
* @return The connection mantained here at time of disconnect. Null if
* there was no connection cached internally.
*/
public Connection manualDisconnect() { public Connection manualDisconnect() {
if ( isClosed ) { if ( isClosed ) {
throw new IllegalStateException( "cannot manually disconnect because logical connection is already closed" ); throw new IllegalStateException( "cannot manually disconnect because logical connection is already closed" );
} }
releaseProxies();
Connection c = physicalConnection; Connection c = physicalConnection;
jdbcResourceRegistry.releaseResources(); jdbcResourceRegistry.releaseResources();
releaseConnection(); releaseConnection();
return c; return c;
} }
/** private void releaseNonDurableObservers() {
* Manually reconnect the underlying JDBC Connection. Should be called at Iterator observers = this.observers.iterator();
* some point after manualDisconnect(). while ( observers.hasNext() ) {
* <p/> if ( NonDurableConnectionObserver.class.isInstance( observers.next() ) ) {
* This form is used for user-supplied connections. observers.remove();
*/ }
public void reconnect(Connection suppliedConnection) { }
}
@Override
public void manualReconnect(Connection suppliedConnection) {
if ( isClosed ) { if ( isClosed ) {
throw new IllegalStateException( "cannot manually reconnect because logical connection is already closed" ); throw new IllegalStateException( "cannot manually reconnect because logical connection is already closed" );
} }
@ -401,29 +380,65 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
} }
} }
@Override
public boolean isAutoCommit() {
if ( !isOpen() || ! isPhysicallyConnected() ) {
return true;
}
try {
return getConnection().getAutoCommit();
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert( e, "could not inspect JDBC autocommit mode" );
}
}
@Override
public void notifyObserversStatementPrepared() {
for ( ConnectionObserver observer : observers ) {
observer.statementPrepared();
}
}
@Override
public boolean isReadyForSerialization() { public boolean isReadyForSerialization() {
return isUserSuppliedConnection ? return isUserSuppliedConnection
! isPhysicallyConnected() : ? ! isPhysicallyConnected()
! getResourceRegistry().hasRegisteredResources() : ! getResourceRegistry().hasRegisteredResources();
;
} }
public void serialize(ObjectOutputStream oos) throws IOException { public void serialize(ObjectOutputStream oos) throws IOException {
oos.writeBoolean( isUserSuppliedConnection ); oos.writeBoolean( isUserSuppliedConnection );
oos.writeBoolean( isClosed ); oos.writeBoolean( isClosed );
List<ConnectionObserver> durableConnectionObservers = new ArrayList<ConnectionObserver>();
for ( ConnectionObserver observer : observers ) {
if ( ! NonDurableConnectionObserver.class.isInstance( observer ) ) {
durableConnectionObservers.add( observer );
}
}
oos.writeInt( durableConnectionObservers.size() );
for ( ConnectionObserver observer : durableConnectionObservers ) {
oos.writeObject( observer );
}
} }
public static LogicalConnectionImpl deserialize(ObjectInputStream ois, public static LogicalConnectionImpl deserialize(
JdbcServices jdbcServices, ObjectInputStream ois,
StatisticsImplementor statisticsImplementor, TransactionContext transactionContext) throws IOException, ClassNotFoundException {
ConnectionReleaseMode connectionReleaseMode boolean isUserSuppliedConnection = ois.readBoolean();
) throws IOException { boolean isClosed = ois.readBoolean();
int observerCount = ois.readInt();
List<ConnectionObserver> observers = CollectionHelper.arrayList( observerCount );
for ( int i = 0; i < observerCount; i++ ) {
observers.add( (ConnectionObserver) ois.readObject() );
}
return new LogicalConnectionImpl( return new LogicalConnectionImpl(
connectionReleaseMode, transactionContext.getConnectionReleaseMode(),
jdbcServices, transactionContext.getTransactionEnvironment().getJdbcServices(),
statisticsImplementor, isUserSuppliedConnection,
ois.readBoolean(), isClosed,
ois.readBoolean() observers
); );
} }

View File

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

View File

@ -0,0 +1,223 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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 org.hibernate.AssertionFailure;
import org.hibernate.ScrollMode;
import org.hibernate.TransactionException;
import org.hibernate.cfg.Settings;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.StatementPreparer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Steve Ebersole
*/
class StatementPreparerImpl implements StatementPreparer {
private long transactionTimeOut = -1;
private JdbcCoordinatorImpl jdbcCoordinator;
StatementPreparerImpl(JdbcCoordinatorImpl jdbcCoordinator) {
this.jdbcCoordinator = jdbcCoordinator;
}
protected final Settings settings() {
return jdbcCoordinator.sessionFactory().getSettings();
}
protected final Connection connectionProxy() {
return logicalConnection().getShareableConnectionProxy();
}
protected final LogicalConnectionImplementor logicalConnection() {
return jdbcCoordinator.getLogicalConnection();
}
protected final SQLExceptionHelper sqlExceptionHelper() {
return jdbcCoordinator.getTransactionCoordinator()
.getTransactionContext()
.getTransactionEnvironment()
.getJdbcServices()
.getSqlExceptionHelper();
}
@Override
public PreparedStatement prepareStatement(String sql) {
return buildPreparedStatementPreparationTemplate( sql, false ).prepareStatement();
}
@Override
public PreparedStatement prepareStatement(String sql, final boolean isCallable) {
jdbcCoordinator.executeBatch();
return buildPreparedStatementPreparationTemplate( sql, isCallable ).prepareStatement();
}
private StatementPreparationTemplate buildPreparedStatementPreparationTemplate(String sql, final boolean isCallable) {
return new StatementPreparationTemplate( sql ) {
@Override
protected PreparedStatement doPrepare() throws SQLException {
return isCallable
? connectionProxy().prepareCall( sql )
: connectionProxy().prepareStatement( sql );
}
};
}
private void checkAutoGeneratedKeysSupportEnabled() {
if ( ! settings().isGetGeneratedKeysEnabled() ) {
throw new AssertionFailure( "getGeneratedKeys() support is not enabled" );
}
}
@Override
public PreparedStatement prepareStatement(String sql, final int autoGeneratedKeys) {
if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) {
checkAutoGeneratedKeysSupportEnabled();
}
jdbcCoordinator.executeBatch();
return new StatementPreparationTemplate( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return connectionProxy().prepareStatement( sql, autoGeneratedKeys );
}
}.prepareStatement();
}
@Override
public PreparedStatement prepareStatement(String sql, final String[] columnNames) {
checkAutoGeneratedKeysSupportEnabled();
jdbcCoordinator.executeBatch();
return new StatementPreparationTemplate( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return connectionProxy().prepareStatement( sql, columnNames );
}
}.prepareStatement();
}
@Override
public PreparedStatement prepareQueryStatement(
String sql,
final boolean isCallable,
final ScrollMode scrollMode) {
if ( scrollMode != null && !scrollMode.equals( ScrollMode.FORWARD_ONLY ) ) {
if ( ! settings().isScrollableResultSetsEnabled() ) {
throw new AssertionFailure("scrollable result sets are not enabled");
}
PreparedStatement ps = new QueryStatementPreparationTemplate( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return isCallable
? connectionProxy().prepareCall(
sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY
)
: connectionProxy().prepareStatement(
sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY
);
}
}.prepareStatement();
logicalConnection().getResourceRegistry().registerLastQuery( ps );
return ps;
}
else {
PreparedStatement ps = new QueryStatementPreparationTemplate( sql ) {
public PreparedStatement doPrepare() throws SQLException {
return isCallable
? connectionProxy().prepareCall( sql )
: connectionProxy().prepareStatement( sql );
}
}.prepareStatement();
logicalConnection().getResourceRegistry().registerLastQuery( ps );
return ps;
}
}
@Override
public void setTransactionTimeOut(int timeOut) {
transactionTimeOut = timeOut;
}
@Override
public void unsetTransactionTimeOut() {
transactionTimeOut = -1;
}
private abstract class StatementPreparationTemplate {
protected final String sql;
protected StatementPreparationTemplate(String sql) {
this.sql = sql;
}
public PreparedStatement prepareStatement() {
try {
PreparedStatement preparedStatement = doPrepare();
setStatementTimeout( preparedStatement );
postProcess( preparedStatement );
return preparedStatement;
}
catch ( SQLException e ) {
throw sqlExceptionHelper().convert( e, "could not prepare statement", sql );
}
}
protected abstract PreparedStatement doPrepare() throws SQLException;
public void postProcess(PreparedStatement preparedStatement) throws SQLException {
}
private void setStatementTimeout(PreparedStatement preparedStatement) throws SQLException {
if ( transactionTimeOut > 0 ) {
int timeout = (int) ( transactionTimeOut - ( System.currentTimeMillis() / 1000 ) );
if ( timeout <= 0 ) {
throw new TransactionException( "transaction timeout expired" );
}
else {
preparedStatement.setQueryTimeout( timeout );
}
}
}
}
private abstract class QueryStatementPreparationTemplate extends StatementPreparationTemplate {
protected QueryStatementPreparationTemplate(String sql) {
super( sql );
}
public void postProcess(PreparedStatement preparedStatement) throws SQLException {
super.postProcess( preparedStatement );
setStatementFetchSize( preparedStatement );
}
}
private void setStatementFetchSize(PreparedStatement statement) throws SQLException {
if ( settings().getJdbcFetchSize() != null ) {
statement.setFetchSize( settings().getJdbcFetchSize() );
}
}
}

View File

@ -36,19 +36,19 @@ import java.sql.Statement;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.hibernate.TransactionException;
import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry; import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor; import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.stat.StatisticsImplementor; import org.hibernate.engine.jdbc.spi.NonDurableConnectionObserver;
/** /**
* The {@link InvocationHandler} for intercepting messages to {@link java.sql.Connection} proxies. * The {@link InvocationHandler} for intercepting messages to {@link java.sql.Connection} proxies.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class ConnectionProxyHandler extends AbstractProxyHandler implements InvocationHandler, ConnectionObserver { public class ConnectionProxyHandler
extends AbstractProxyHandler
implements InvocationHandler, NonDurableConnectionObserver {
private static final Logger log = LoggerFactory.getLogger( ConnectionProxyHandler.class ); private static final Logger log = LoggerFactory.getLogger( ConnectionProxyHandler.class );
private LogicalConnectionImplementor logicalConnection; private LogicalConnectionImplementor logicalConnection;
@ -112,6 +112,10 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
return null; return null;
} }
if ( "isClosed".equals( methodName ) ) {
return ! isValid();
}
errorIfInvalid(); errorIfInvalid();
// handle the JDBC 4 Wrapper#isWrapperFor and Wrapper#unwrap calls // handle the JDBC 4 Wrapper#isWrapperFor and Wrapper#unwrap calls
@ -185,9 +189,7 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
} }
private void postProcessPreparedStatement(Statement statement) throws SQLException { private void postProcessPreparedStatement(Statement statement) throws SQLException {
if ( getStatisticsImplementorOrNull() != null ) { logicalConnection.notifyObserversStatementPrepared();
getStatisticsImplementorOrNull().prepareStatement();
}
postProcessStatement( statement ); postProcessStatement( statement );
} }
@ -203,29 +205,25 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
invalidate(); invalidate();
} }
/** // ConnectionObserver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* {@inheritDoc}
*/ @Override
public void physicalConnectionObtained(Connection connection) { public void physicalConnectionObtained(Connection connection) {
} }
/** @Override
* {@inheritDoc}
*/
public void physicalConnectionReleased() { public void physicalConnectionReleased() {
log.info( "logical connection releasing its physical connection"); log.info( "logical connection releasing its physical connection");
} }
/** @Override
* {@inheritDoc}
*/
public void logicalConnectionClosed() { public void logicalConnectionClosed() {
log.info( "*** logical connection closed ***" ); log.info( "*** logical connection closed ***" );
invalidateHandle(); invalidateHandle();
} }
/* package-protected */ @Override
StatisticsImplementor getStatisticsImplementorOrNull() { public void statementPrepared() {
return getLogicalConnection().getStatisticsImplementor(); // N/A
} }
} }

View File

@ -47,4 +47,9 @@ public interface ConnectionObserver {
* The logical connection was closed. * The logical connection was closed.
*/ */
public void logicalConnectionClosed(); public void logicalConnectionClosed();
/**
* Notification of a statement being prepared
*/
public void statementPrepared();
} }

View File

@ -1,42 +1,47 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation. * Lesser General Public License, as published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details. * for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to: * along with this distribution; if not, write to:
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
* */
*/ package org.hibernate.engine.jdbc.spi;
package org.hibernate.jdbc;
import java.sql.Connection;
import java.sql.Connection;
/**
/** * @author Steve Ebersole
* Interface implemented by JDBC connection wrappers in order to give */
* access to the underlying wrapped connection. public class ConnectionObserverAdapter implements ConnectionObserver {
* @Override
* @author Steve Ebersole public void physicalConnectionObtained(Connection connection) {
*/ }
public interface ConnectionWrapper {
/** @Override
* Get a reference to the wrapped connection. public void physicalConnectionReleased() {
* }
* @return The wrapped connection.
*/ @Override
public Connection getWrappedConnection(); public void logicalConnectionClosed() {
} }
@Override
public void statementPrepared() {
}
}

View File

@ -1,83 +0,0 @@
/*
* 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.spi;
import java.io.Serializable;
import java.sql.Connection;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Transaction;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.transaction.synchronization.CallbackCoordinator;
/**
* Acts as the SPI for the mediary between "entity-mode related" sessions in terms of
* their interaction with the JDBC data store.
*
* @author Gail Badner
*/
public interface JDBCContext extends Serializable {
// TODO: Document these methods...
CallbackCoordinator getJtaSynchronizationCallbackCoordinator();
void cleanUpJtaSynchronizationCallbackCoordinator();
SessionFactoryImplementor getFactory();
ConnectionManager getConnectionManager();
Connection connection() throws HibernateException;
boolean registerCallbackIfNecessary();
boolean registerSynchronizationIfPossible();
boolean isTransactionInProgress();
Transaction getTransaction() throws HibernateException;
void beforeTransactionCompletion(Transaction tx);
void afterTransactionBegin(Transaction tx);
void afterTransactionCompletion(boolean success, Transaction tx);
void afterNontransactionalQuery(boolean success);
public static interface Context extends TransactionFactory.Context {
/**
* We cannot rely upon this method being called! It is only
* called if we are using Hibernate Transaction API.
*/
public void afterTransactionBegin(Transaction tx);
public void beforeTransactionCompletion(Transaction tx);
public void afterTransactionCompletion(boolean success, Transaction tx);
public ConnectionReleaseMode getConnectionReleaseMode();
public boolean isAutoCloseSessionEnabled();
}
}

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,35 +20,32 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.transaction; package org.hibernate.engine.jdbc.spi;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.engine.SessionFactoryImplementor;
import java.io.Serializable;
/** /**
* {@link TransactionManagerLookup} strategy for Orion * Access to services needed in the context of processing JDBC requests.
* *
* @author Gavin King * @author Steve Ebersole
*/ */
public class OrionTransactionManagerLookup extends JNDITransactionManagerLookup { public interface JdbcContext extends Serializable {
public SessionFactoryImplementor getSessionFactory();
public ConnectionReleaseMode getConnectionReleaseMode();
/** public boolean isClosed();
* {@inheritDoc}
*/
protected String getName() {
return "java:comp/UserTransaction";
}
/** public boolean isFlushModeNever();
* {@inheritDoc}
*/
public String getUserTransactionName() {
return "java:comp/UserTransaction";
}
public boolean isFlushBeforeCompletionEnabled();
public void managedFlush();
public boolean shouldAutoClose();
public void managedClose();
} }

View File

@ -0,0 +1,96 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.spi;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.jdbc.Work;
import java.io.Serializable;
import java.sql.Connection;
/**
* Coordinates JDBC-related activities.
*
* @author Steve Ebersole
*/
public interface JdbcCoordinator extends Serializable {
/**
* Retrieve the transaction coordinator associated with this JDBC coordinator.
*
* @return The transaction coordinator
*/
public TransactionCoordinator getTransactionCoordinator();
/**
* Retrieves the logical connection associated with this JDBC coordinator.
*
* @return The logical connection
*/
public LogicalConnectionImplementor getLogicalConnection();
/**
* Get a batch instance.
*
* @param key The unique batch key.
*
* @return The batch
*/
public Batch getBatch(BatchKey key);
public void abortBatch();
/**
* Obtain the statement preparer associated with this JDBC coordinator.
*
* @return This coordinator's statement preparer
*/
public StatementPreparer getStatementPreparer();
/**
* Callback to let us know that a flush is beginning. We use this fact
* to temporarily circumvent aggressive connection releasing until after
* the flush cycle is complete {@link #flushEnding()}
*/
public void flushBeginning();
/**
* Callback to let us know that a flush is ending. We use this fact to
* stop circumventing aggressive releasing connections.
*/
public void flushEnding();
public Connection close();
public void afterTransaction();
public void coordinateWork(Work work);
public void executeBatch();
public void cancelLastQuery();
public void setTransactionTimeOut(int timeout);
}

View File

@ -23,6 +23,7 @@
*/ */
package org.hibernate.engine.jdbc.spi; package org.hibernate.engine.jdbc.spi;
import java.io.Serializable;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
@ -31,7 +32,7 @@ import java.sql.Statement;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface JdbcResourceRegistry { public interface JdbcResourceRegistry extends Serializable {
/** /**
* Register a JDBC statement. * Register a JDBC statement.
* *

View File

@ -31,7 +31,7 @@ import java.sql.Connection;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface LogicalConnection { public interface LogicalConnection extends Serializable {
/** /**
* Is this logical connection open? Another phraseology sometimes used is: "are we * Is this logical connection open? Another phraseology sometimes used is: "are we
* logically connected"? * logically connected"?
@ -55,10 +55,27 @@ public interface LogicalConnection {
* connection has either not yet been obtained (non-UserSuppliedConnectionProvider) * connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
* or has previously been aggressively released. * or has previously been aggressively released.
* *
* @todo ?? Move this to {@link LogicalConnectionImplementor} in lieu of {@link #getShareableConnectionProxy} and {@link #getDistinctConnectionProxy} ??
*
* @return The current Connection. * @return The current Connection.
*/ */
public Connection getConnection(); public Connection getConnection();
/**
* Retrieves the shareable connection proxy (see {@link org.hibernate.engine.jdbc.internal.proxy} for details).
*
* @return The shareable connection proxy.
*/
public Connection getShareableConnectionProxy();
/**
* Retrieves a distinct connection proxy (see {@link org.hibernate.engine.jdbc.internal.proxy} for details). It
* is distinct in that it is not shared with others unless the caller explicitly shares it.
*
* @return The distinct connection proxy.
*/
public Connection getDistinctConnectionProxy();
/** /**
* Release the underlying connection and clean up any other resources associated * Release the underlying connection and clean up any other resources associated
* with this logical connection. * with this logical connection.
@ -68,4 +85,6 @@ public interface LogicalConnection {
* @return The physical connection which was being used. * @return The physical connection which was being used.
*/ */
public Connection close(); public Connection close();
public void afterTransaction();
} }

View File

@ -24,8 +24,11 @@
package org.hibernate.engine.jdbc.spi; package org.hibernate.engine.jdbc.spi;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler;
import org.hibernate.stat.StatisticsImplementor; import org.hibernate.stat.StatisticsImplementor;
import java.sql.Connection;
/** /**
* The "internal" contract for LogicalConnection * The "internal" contract for LogicalConnection
* *
@ -39,13 +42,6 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
*/ */
public JdbcServices getJdbcServices(); public JdbcServices getJdbcServices();
/**
* Obtains the statistics implementor.
*
* @return the statistics implementor
*/
public StatisticsImplementor getStatisticsImplementor();
/** /**
* Obtains the JDBC resource registry associated with this logical connection. * Obtains the JDBC resource registry associated with this logical connection.
* *
@ -60,6 +56,13 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
*/ */
public void addObserver(ConnectionObserver observer); public void addObserver(ConnectionObserver observer);
/**
* Remove an observer
*
* @param connectionObserver The observer to remove.
*/
public void removeObserver(ConnectionObserver connectionObserver);
/** /**
* The release mode under which this logical connection is operating. * The release mode under which this logical connection is operating.
* *
@ -91,5 +94,26 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
*/ */
public void enableReleases(); public void enableReleases();
/**
* Manually disconnect the underlying JDBC Connection. The assumption here
* is that the manager will be reconnected at a later point in time.
*
* @return The connection maintained here at time of disconnect. Null if
* there was no connection cached internally.
*/
public Connection manualDisconnect();
/**
* Manually reconnect the underlying JDBC Connection. Should be called at some point after manualDisconnect().
*
* @param suppliedConnection For user supplied connection strategy the user needs to hand us the connection
* with which to reconnect. It is an error to pass a connection in the other strategies.
*/
public void manualReconnect(Connection suppliedConnection);
public boolean isAutoCommit();
public boolean isReadyForSerialization();
public void notifyObserversStatementPrepared();
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,23 +20,14 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.transaction; package org.hibernate.engine.jdbc.spi;
/** /**
* A {@link TransactionManagerLookup} lookup strategy for JBoss AS. * Additional optional contract for connection observers to indicate that they should be released when the physical
* connection is released.
* *
* @author Gavin King * @author Steve Ebersole
*/ */
public final class JBossTransactionManagerLookup extends JNDITransactionManagerLookup { public interface NonDurableConnectionObserver extends ConnectionObserver {
protected String getName() {
return "java:/TransactionManager";
}
public String getUserTransactionName() {
return "UserTransaction";
}
} }

View File

@ -23,6 +23,7 @@
*/ */
package org.hibernate.engine.jdbc.spi; package org.hibernate.engine.jdbc.spi;
import java.io.Serializable;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.SQLWarning; import java.sql.SQLWarning;
@ -41,7 +42,7 @@ import org.hibernate.util.StringHelper;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SQLExceptionHelper { public class SQLExceptionHelper implements Serializable {
private static final Logger log = LoggerFactory.getLogger( SQLExceptionHelper.class ); private static final Logger log = LoggerFactory.getLogger( SQLExceptionHelper.class );
public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception"; public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";

View File

@ -0,0 +1,97 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.spi;
import org.hibernate.ScrollMode;
import java.sql.PreparedStatement;
/**
* @author Steve Ebersole
*/
public interface StatementPreparer {
/**
* Prepare a statement.
*
* @param sql The SQL the statement to be prepared
*
* @return the prepared statement
*/
public PreparedStatement prepareStatement(String sql);
/**
* Prepare a statement.
*
* @param sql The SQL the statement to be prepared
* @param isCallable Whether to prepare as a callable statement.
*
* @return the prepared statement
*/
public PreparedStatement prepareStatement(String sql, boolean isCallable);
/**
* Get a prepared statement to use for inserting using JDBC3
* {@link java.sql.PreparedStatement#getGeneratedKeys getGeneratedKeys} processing.
*
* @param sql - the SQL for the statement to be prepared
* @param autoGeneratedKeys - a flag indicating whether auto-generated keys should be returned; one of<ul>
* <li>{@link PreparedStatement#RETURN_GENERATED_KEYS}</li>
* <li>{@link PreparedStatement#NO_GENERATED_KEYS}</li>
* </li>
*
* @return the prepared statement
*
* @see java.sql.Connection#prepareStatement(String, int)
*/
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys);
/**
* Get a prepared statement to use for inserting using JDBC3
* {@link java.sql.PreparedStatement#getGeneratedKeys getGeneratedKeys} processing.
*
* @param sql - the SQL for the statement to be prepared
* @param columnNames The name of the columns to be returned in the generated keys result set.
*
* @return the prepared statement
*
* @see java.sql.Connection#prepareStatement(String, String[])
*/
public PreparedStatement prepareStatement(String sql, String[] columnNames);
/**
* Get a prepared statement for use in loading / querying.
*
* @param sql The SQL the statement to be prepared
* @param isCallable Whether to prepare as a callable statement.
* @param scrollMode (optional) scroll mode to be applied to the resulting result set; may be null to indicate
* no scrolling should be applied.
*
* @return the prepared statement
*/
public PreparedStatement prepareQueryStatement(String sql, boolean isCallable, ScrollMode scrollMode);
public void setTransactionTimeOut(int timeout);
public void unsetTransactionTimeOut();
}

View File

@ -198,7 +198,7 @@ public class NativeSQLQueryPlan implements Serializable {
session ); session );
String sql = queryParameters.getFilteredSQL(); String sql = queryParameters.getFilteredSQL();
ps = session.getJDBCContext().getConnectionManager().prepareStatement( sql, false ); ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
try { try {
int col = 1; int col = 1;

View File

@ -1,307 +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.engine.transaction;
import java.sql.Connection;
import java.sql.SQLException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.SystemException;
import javax.transaction.NotSupportedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.exception.SQLExceptionConverter;
/**
* Class which provides the isolation semantics required by
* an {@link IsolatedWork}. Processing comes in two flavors:<ul>
* <li>{@link #doIsolatedWork} : makes sure the work to be done is
* performed in a seperate, distinct transaction</li>
* <li>{@link #doNonTransactedWork} : makes sure the work to be
* done is performed outside the scope of any transaction</li>
* </ul>
*
* @author Steve Ebersole
*/
public class Isolater {
private static final Logger log = LoggerFactory.getLogger( Isolater.class );
/**
* Ensures that all processing actually performed by the given work will
* occur on a seperate transaction.
*
* @param work The work to be performed.
* @param session The session from which this request is originating.
* @throws HibernateException
*/
public static void doIsolatedWork(IsolatedWork work, SessionImplementor session) throws HibernateException {
boolean isJta = session.getFactory().getTransactionManager() != null;
if ( isJta ) {
new JtaDelegate( session ).delegateWork( work, true );
}
else {
new JdbcDelegate( session ).delegateWork( work, true );
}
}
/**
* Ensures that all processing actually performed by the given work will
* occur outside of a transaction.
*
* @param work The work to be performed.
* @param session The session from which this request is originating.
* @throws HibernateException
*/
public static void doNonTransactedWork(IsolatedWork work, SessionImplementor session) throws HibernateException {
boolean isJta = session.getFactory().getTransactionManager() != null;
if ( isJta ) {
new JtaDelegate( session ).delegateWork( work, false );
}
else {
new JdbcDelegate( session ).delegateWork( work, false );
}
}
// should be ok performance-wise to generate new delegate instances for each
// request since these are locally stack-scoped. Besides, it makes the code
// much easier to read than the old TransactionHelper stuff...
private static interface Delegate {
public void delegateWork(IsolatedWork work, boolean transacted) throws HibernateException;
}
/**
* An isolation delegate for JTA-based transactions. Essentially susepnds
* any current transaction, does the work in a new transaction, and then
* resumes the initial transaction (if there was one).
*/
public static class JtaDelegate implements Delegate {
private final SessionImplementor session;
public JtaDelegate(SessionImplementor session) {
this.session = session;
}
public void delegateWork(IsolatedWork work, boolean transacted) throws HibernateException {
TransactionManager transactionManager = session.getFactory().getTransactionManager();
try {
// First we suspend any current JTA transaction
Transaction surroundingTransaction = transactionManager.suspend();
if ( log.isDebugEnabled() ) {
log.debug( "surrounding JTA transaction suspended [" + surroundingTransaction + "]" );
}
boolean hadProblems = false;
try {
// then peform the requested work
if ( transacted ) {
doTheWorkInNewTransaction( work, transactionManager );
}
else {
doTheWorkInNoTransaction( work );
}
}
catch ( HibernateException e ) {
hadProblems = true;
throw e;
}
finally {
try {
transactionManager.resume( surroundingTransaction );
if ( log.isDebugEnabled() ) {
log.debug( "surrounding JTA transaction resumed [" + surroundingTransaction + "]" );
}
}
catch( Throwable t ) {
// if the actually work had an error use that, otherwise error based on t
if ( !hadProblems ) {
//noinspection ThrowFromFinallyBlock
throw new HibernateException( "Unable to resume previously suspended transaction", t );
}
}
}
}
catch ( SystemException e ) {
throw new HibernateException( "Unable to suspend current JTA transaction", e );
}
}
private void doTheWorkInNewTransaction(IsolatedWork work, TransactionManager transactionManager) {
try {
// start the new isolated transaction
transactionManager.begin();
try {
doTheWork( work );
// if everythign went ok, commit the isolated transaction
transactionManager.commit();
}
catch ( Exception e ) {
try {
transactionManager.rollback();
}
catch ( Exception ignore ) {
log.info( "Unable to rollback isolated transaction on error [" + e + "] : [" + ignore + "]" );
}
}
}
catch ( SystemException e ) {
throw new HibernateException( "Unable to start isolated transaction", e );
}
catch ( NotSupportedException e ) {
throw new HibernateException( "Unable to start isolated transaction", e );
}
}
private void doTheWorkInNoTransaction(IsolatedWork work) {
doTheWork( work );
}
private void doTheWork(IsolatedWork work) {
try {
// obtain our isolated connection
Connection connection = session.getFactory().getConnectionProvider().getConnection();
try {
// do the actual work
work.doWork( connection );
}
catch ( HibernateException e ) {
throw e;
}
catch ( Exception e ) {
throw new HibernateException( "Unable to perform isolated work", e );
}
finally {
try {
// no matter what, release the connection (handle)
session.getFactory().getConnectionProvider().closeConnection( connection );
}
catch ( Throwable ignore ) {
log.info( "Unable to release isolated connection [" + ignore + "]" );
}
}
}
catch ( SQLException sqle ) {
throw sqlExceptionHelper().convert(
sqle,
"unable to obtain isolated JDBC connection"
);
}
}
private SQLExceptionHelper sqlExceptionHelper() {
return session.getFactory().getSQLExceptionHelper();
}
}
/**
* An isolation delegate for JDBC-based transactions. Basically just
* grabs a new connection and does the work on that.
*/
public static class JdbcDelegate implements Delegate {
private final SessionImplementor session;
public JdbcDelegate(SessionImplementor session) {
this.session = session;
}
public void delegateWork(IsolatedWork work, boolean transacted) throws HibernateException {
boolean wasAutoCommit = false;
try {
Connection connection = session.getFactory().getConnectionProvider().getConnection();
try {
if ( transacted ) {
if ( connection.getAutoCommit() ) {
wasAutoCommit = true;
connection.setAutoCommit( false );
}
}
work.doWork( connection );
if ( transacted ) {
connection.commit();
}
}
catch( Exception e ) {
try {
if ( transacted && !connection.isClosed() ) {
connection.rollback();
}
}
catch( Exception ignore ) {
log.info( "unable to rollback connection on exception [" + ignore + "]" );
}
if ( e instanceof HibernateException ) {
throw ( HibernateException ) e;
}
else if ( e instanceof SQLException ) {
throw sqlExceptionHelper().convert(
( SQLException ) e,
"error performing isolated work"
);
}
else {
throw new HibernateException( "error performing isolated work", e );
}
}
finally {
if ( transacted && wasAutoCommit ) {
try {
connection.setAutoCommit( true );
}
catch( Exception ignore ) {
log.trace( "was unable to reset connection back to auto-commit" );
}
}
try {
session.getFactory().getConnectionProvider().closeConnection( connection );
}
catch ( Exception ignore ) {
log.info( "Unable to release isolated connection [" + ignore + "]" );
}
}
}
catch ( SQLException sqle ) {
throw sqlExceptionHelper().convert(
sqle,
"unable to obtain isolated JDBC connection"
);
}
}
private SQLExceptionHelper sqlExceptionHelper() {
return session.getFactory().getSQLExceptionHelper();
}
}
}

View File

@ -21,12 +21,12 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.engine.transaction; package org.hibernate.engine.transaction.internal;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
/** /**
* TODO : javadoc * Indicates an attempt to register a null synchronization. Basically a glorified {@link NullPointerException}
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */

View File

@ -1,7 +1,7 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc. * distributed under license by Red Hat Inc.
@ -21,7 +21,9 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.engine.transaction; package org.hibernate.engine.transaction.internal;
import org.hibernate.engine.transaction.spi.SynchronizationRegistry;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import javax.transaction.Synchronization; import javax.transaction.Synchronization;
@ -29,25 +31,17 @@ import javax.transaction.Synchronization;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
/** /**
* Manages a registry of {@link Synchronization Synchronizations}. * Manages a registry of {@link Synchronization Synchronizations}.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SynchronizationRegistry { public class SynchronizationRegistryImpl implements SynchronizationRegistry {
private static final Logger log = LoggerFactory.getLogger( SynchronizationRegistry.class ); private static final Logger log = LoggerFactory.getLogger( SynchronizationRegistryImpl.class );
private LinkedHashSet<Synchronization> synchronizations; private LinkedHashSet<Synchronization> synchronizations;
/** @Override
* Register a user {@link Synchronization} callback for this transaction.
*
* @param synchronization The synchronization callback to register.
*
* @throws HibernateException
*/
public void registerSynchronization(Synchronization synchronization) { public void registerSynchronization(Synchronization synchronization) {
if ( synchronization == null ) { if ( synchronization == null ) {
throw new NullSynchronizationException(); throw new NullSynchronizationException();
@ -63,10 +57,7 @@ public class SynchronizationRegistry {
} }
} }
/** @Override
* Delegate {@link Synchronization#beforeCompletion} calls to {@link #registerSynchronization registered}
* {@link Synchronization Synchronizations}
*/
public void notifySynchronizationsBeforeTransactionCompletion() { public void notifySynchronizationsBeforeTransactionCompletion() {
if ( synchronizations != null ) { if ( synchronizations != null ) {
for ( Synchronization synchronization : synchronizations ) { for ( Synchronization synchronization : synchronizations ) {
@ -80,12 +71,7 @@ public class SynchronizationRegistry {
} }
} }
/** @Override
* Delegate {@link Synchronization#afterCompletion} calls to {@link #registerSynchronization registered}
* {@link Synchronization Synchronizations}
*
* @param status The transaction status (if known) per {@link javax.transaction.Status}
*/
public void notifySynchronizationsAfterTransactionCompletion(int status) { public void notifySynchronizationsAfterTransactionCompletion(int status) {
if ( synchronizations != null ) { if ( synchronizations != null ) {
for ( Synchronization synchronization : synchronizations ) { for ( Synchronization synchronization : synchronizations ) {
@ -98,4 +84,14 @@ public class SynchronizationRegistry {
} }
} }
} }
/**
* Package-protected access to clear registered synchronizations.
*/
void clearSynchronizations() {
if ( synchronizations != null ) {
synchronizations.clear();
synchronizations = null;
}
}
} }

View File

@ -0,0 +1,348 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.internal;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.ResourceClosedException;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.engine.transaction.spi.SynchronizationRegistry;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
import org.hibernate.engine.transaction.spi.TransactionFactory;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.engine.transaction.spi.TransactionObserver;
import org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization;
import org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorImpl;
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.util.CollectionHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
/**
* Standard implementation of the Hibernate {@link TransactionCoordinator}
* <p/>
* IMPL NOTE : Custom serialization handling!
*
* @author Steve Ebersole
*/
public class TransactionCoordinatorImpl implements TransactionCoordinator {
private static final Logger log = LoggerFactory.getLogger( TransactionCoordinatorImpl.class );
private final transient TransactionContext transactionContext;
private final transient JdbcCoordinatorImpl jdbcCoordinator;
private final transient List<TransactionObserver> observers;
private final transient SynchronizationRegistryImpl synchronizationRegistry;
private transient TransactionImplementor currentHibernateTransaction;
private transient SynchronizationCallbackCoordinatorImpl callbackCoordinator;
private transient boolean open = true;
private transient boolean synchronizationRegistered;
private transient boolean ownershipTaken;
public TransactionCoordinatorImpl(
Connection userSuppliedConnection,
TransactionContext transactionContext) {
this.transactionContext = transactionContext;
this.jdbcCoordinator = new JdbcCoordinatorImpl( userSuppliedConnection, this );
this.observers = new ArrayList<TransactionObserver>();
this.synchronizationRegistry = new SynchronizationRegistryImpl();
reset();
final boolean registerSynchronization = transactionContext.isAutoCloseSessionEnabled()
|| transactionContext.isFlushBeforeCompletionEnabled()
|| transactionContext.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION;
if ( registerSynchronization ) {
pulse();
}
}
public TransactionCoordinatorImpl(
TransactionContext transactionContext,
JdbcCoordinatorImpl jdbcCoordinator,
List<TransactionObserver> observers) {
this.transactionContext = transactionContext;
this.jdbcCoordinator = jdbcCoordinator;
this.observers = observers;
this.synchronizationRegistry = new SynchronizationRegistryImpl();
reset();
}
/**
* Reset the internal state.
*/
public void reset() {
synchronizationRegistered = false;
ownershipTaken = false;
if ( currentHibernateTransaction != null ) {
currentHibernateTransaction.invalidate();
}
currentHibernateTransaction = transactionFactory().createTransaction( this );
// IMPL NOTE : reset clears synchronizations (following jta spec), but not observers!
synchronizationRegistry.clearSynchronizations();
}
public void afterTransaction(TransactionImplementor hibernateTransaction, int status) {
log.trace( "after transaction completion" );
final boolean success = JtaStatusHelper.isCommitted( status );
// todo : handle stats as observer?
// as is this messes up unit tests which do not build a sf
// if ( sessionFactory().getStatistics().isStatisticsEnabled() ) {
// sessionFactory().getStatisticsImplementor().endTransaction( success );
// }
getJdbcCoordinator().afterTransaction();
getTransactionContext().afterTransactionCompletion( hibernateTransaction, success );
sendAfterTransactionCompletionNotifications( hibernateTransaction, status );
reset();
}
private SessionFactoryImplementor sessionFactory() {
return transactionContext.getTransactionEnvironment().getSessionFactory();
}
public boolean isSynchronizationRegistered() {
return synchronizationRegistered;
}
@Override
@SuppressWarnings( {"unchecked"})
public boolean isTransactionInProgress() {
return getTransaction().isActive() &&
transactionFactory().getJoinStatus( this, getTransaction() ) == JoinStatus.JOINED;
}
@Override
public TransactionContext getTransactionContext() {
return transactionContext;
}
@Override
public JdbcCoordinator getJdbcCoordinator() {
return jdbcCoordinator;
}
private TransactionFactory transactionFactory() {
return getTransactionEnvironment().getTransactionFactory();
}
private TransactionEnvironment getTransactionEnvironment() {
return getTransactionContext().getTransactionEnvironment();
}
@Override
public TransactionImplementor getTransaction() {
if ( ! open ) {
throw new ResourceClosedException( "This TransactionCoordinator has been closed" );
}
pulse();
return currentHibernateTransaction;
}
public void afterNonTransactionalQuery(boolean success) {
// check to see if the connection is in auto-commit mode (no connection means aggressive connection
// release outside a JTA transaction context, so MUST be autocommit mode)
boolean isAutocommit = getJdbcCoordinator().getLogicalConnection().isAutoCommit();
getJdbcCoordinator().getLogicalConnection().afterTransaction();
if ( isAutocommit ) {
for ( TransactionObserver observer : observers ) {
observer.afterCompletion( success, this.getTransaction() );
}
}
}
@Override
public void resetJoinStatus() {
getTransaction().resetJoinStatus();
}
@SuppressWarnings({ "unchecked" })
private void attemptToRegisterJtaSync() {
if ( synchronizationRegistered ) {
return;
}
// Has the local transaction (Hibernate facade) taken on the responsibility of driving the transaction inflow?
if ( currentHibernateTransaction.isInitiator() ) {
return;
}
// IMPL NOTE : At this point the local callback is the "maybe" one. The only time that needs to change is if
// we are able to successfully register the transaction synchronization in which case the local callback would become
// non driving. To that end, the following checks are simply opt outs where we are unable to register the
// synchronization
JtaPlatform jtaPlatform = getTransactionEnvironment().getJtaPlatform();
if ( jtaPlatform == null ) {
// if no jta platform was registered we wont be able to register a jta synchronization
return;
}
// Can we resister a synchronization
if ( ! jtaPlatform.canRegisterSynchronization() ) {
log.trace( "registered JTA platform says we cannot currently resister synchronization; skipping" );
return;
}
// Should we resister a synchronization
if ( ! transactionFactory().isJoinableJtaTransaction( this, currentHibernateTransaction ) ) {
log.trace( "TransactionFactory reported no JTA transaction to join; skipping Synchronization registration" );
return;
}
jtaPlatform.registerSynchronization( new RegisteredSynchronization( getSynchronizationCallbackCoordinator() ) );
synchronizationRegistered = true;
log.debug( "successfully registered Synchronization" );
}
@Override
public SynchronizationCallbackCoordinator getSynchronizationCallbackCoordinator() {
if ( callbackCoordinator == null ) {
callbackCoordinator = new SynchronizationCallbackCoordinatorImpl( this );
}
return callbackCoordinator;
}
public void pulse() {
log.trace( "Starting transaction coordinator pulse" );
if ( transactionFactory().compatibleWithJtaSynchronization() ) {
// the configured transaction strategy says it supports callbacks via JTA synchronization, so attempt to
// register JTA synchronization if possible
attemptToRegisterJtaSync();
}
}
public Connection close() {
open = false;
reset();
observers.clear();
return jdbcCoordinator.close();
}
public SynchronizationRegistry getSynchronizationRegistry() {
return synchronizationRegistry;
}
public void addObserver(TransactionObserver observer) {
observers.add( observer );
}
@Override
@SuppressWarnings( {"unchecked"})
public boolean isTransactionJoinable() {
return transactionFactory().isJoinableJtaTransaction( this, currentHibernateTransaction );
}
@Override
@SuppressWarnings( {"unchecked"})
public boolean isTransactionJoined() {
return transactionFactory().getJoinStatus( this, currentHibernateTransaction ) == JoinStatus.JOINED;
}
public void setRollbackOnly() {
getTransaction().markRollbackOnly();
}
@Override
public boolean takeOwnership() {
if ( ownershipTaken ) {
return false;
}
else {
ownershipTaken = true;
return true;
}
}
@Override
public void sendAfterTransactionBeginNotifications(TransactionImplementor hibernateTransaction) {
for ( TransactionObserver observer : observers ) {
observer.afterBegin( currentHibernateTransaction );
}
}
@Override
public void sendBeforeTransactionCompletionNotifications(TransactionImplementor hibernateTransaction) {
synchronizationRegistry.notifySynchronizationsBeforeTransactionCompletion();
for ( TransactionObserver observer : observers ) {
observer.beforeCompletion( hibernateTransaction );
}
}
@Override
public void sendAfterTransactionCompletionNotifications(TransactionImplementor hibernateTransaction, int status) {
final boolean successful = JtaStatusHelper.isCommitted( status );
for ( TransactionObserver observer : observers ) {
observer.afterCompletion( successful, hibernateTransaction );
}
synchronizationRegistry.notifySynchronizationsAfterTransactionCompletion( status );
}
// serialization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void serialize(ObjectOutputStream oos) throws IOException {
jdbcCoordinator.serialize( oos );
oos.writeInt( observers.size() );
for ( TransactionObserver observer : observers ) {
oos.writeObject( observer );
}
}
public static TransactionCoordinatorImpl deserialize(
ObjectInputStream ois,
TransactionContext transactionContext) throws ClassNotFoundException, IOException {
final JdbcCoordinatorImpl jdbcCoordinator = JdbcCoordinatorImpl.deserialize( ois, transactionContext );
final int observerCount = ois.readInt();
final List<TransactionObserver> observers = CollectionHelper.arrayList( observerCount );
for ( int i = 0; i < observerCount; i++ ) {
observers.add( (TransactionObserver) ois.readObject() );
}
final TransactionCoordinatorImpl transactionCoordinator = new TransactionCoordinatorImpl( transactionContext, jdbcCoordinator, observers );
jdbcCoordinator.afterDeserialize( transactionCoordinator );
return transactionCoordinator;
}
}

View File

@ -0,0 +1,96 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.internal;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory;
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
import org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory;
import org.hibernate.engine.transaction.spi.TransactionFactory;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.spi.ServiceInitiator;
import org.hibernate.service.spi.ServiceRegistry;
/**
* Standard instantiator for the standard {@link TransactionFactory} service.
*
* @author Steve Ebersole
*/
public class TransactionFactoryInitiator implements ServiceInitiator<TransactionFactory> {
private static final Logger log = LoggerFactory.getLogger( TransactionFactoryInitiator.class );
public static final TransactionFactoryInitiator INSTANCE = new TransactionFactoryInitiator();
@Override
public Class<TransactionFactory> getServiceInitiated() {
return TransactionFactory.class;
}
@Override
public TransactionFactory initiateService(Map configVales, ServiceRegistry registry) {
final Object strategy = configVales.get( Environment.TRANSACTION_STRATEGY );
if ( TransactionFactory.class.isInstance( strategy ) ) {
return (TransactionFactory) strategy;
}
if ( strategy == null ) {
log.info( "Using default transaction strategy (direct JDBC transactions)" );
return new JdbcTransactionFactory();
}
final String strategyClassName = mapLegacyNames( strategy.toString() );
log.info( "Transaction strategy: " + strategyClassName );
ClassLoaderService classLoaderService = registry.getService( ClassLoaderService.class );
try {
return (TransactionFactory) classLoaderService.classForName( strategyClassName ).newInstance();
}
catch ( Exception e ) {
throw new HibernateException( "Unable to instantiate specified TransactionFactory class [" + strategyClassName + "]", e );
}
}
private String mapLegacyNames(String name) {
if ( "org.hibernate.transaction.JDBCTransactionFactory".equals( name ) ) {
return JdbcTransactionFactory.class.getName();
}
if ( "org.hibernate.transaction.JTATransactionFactory".equals( name ) ) {
return JtaTransactionFactory.class.getName();
}
if ( "org.hibernate.transaction.CMTTransactionFactory".equals( name ) ) {
return CMTTransactionFactory.class.getName();
}
return name;
}
}

View File

@ -0,0 +1,123 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.internal.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.jdbc.Work;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
/**
* The isolation delegate for JDBC {@link Connection} based transactions
*
* @author Steve Ebersole
*/
public class JdbcIsolationDelegate implements IsolationDelegate {
private static final Logger log = LoggerFactory.getLogger( JdbcIsolationDelegate.class );
private final TransactionCoordinator transactionCoordinator;
public JdbcIsolationDelegate(TransactionCoordinator transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator;
}
protected ConnectionProvider connectionProvider() {
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getJdbcServices().getConnectionProvider();
}
protected SQLExceptionHelper sqlExceptionHelper() {
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getJdbcServices().getSqlExceptionHelper();
}
@Override
public void delegateWork(Work work, boolean transacted) throws HibernateException {
boolean wasAutoCommit = false;
try {
// todo : should we use a connection proxy here?
Connection connection = connectionProvider().getConnection();
try {
if ( transacted ) {
if ( connection.getAutoCommit() ) {
wasAutoCommit = true;
connection.setAutoCommit( false );
}
}
work.execute( connection );
if ( transacted ) {
connection.commit();
}
}
catch ( Exception e ) {
try {
if ( transacted && !connection.isClosed() ) {
connection.rollback();
}
}
catch ( Exception ignore ) {
log.info( "unable to rollback connection on exception [" + ignore + "]" );
}
if ( e instanceof HibernateException ) {
throw (HibernateException) e;
}
else if ( e instanceof SQLException ) {
throw sqlExceptionHelper().convert( (SQLException) e, "error performing isolated work" );
}
else {
throw new HibernateException( "error performing isolated work", e );
}
}
finally {
if ( transacted && wasAutoCommit ) {
try {
connection.setAutoCommit( true );
}
catch ( Exception ignore ) {
log.trace( "was unable to reset connection back to auto-commit" );
}
}
try {
connectionProvider().closeConnection( connection );
}
catch ( Exception ignore ) {
log.info( "Unable to release isolated connection [" + ignore + "]" );
}
}
}
catch ( SQLException sqle ) {
throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" );
}
}
}

View File

@ -0,0 +1,208 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007-2011, 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.transaction.internal.jdbc;
import org.hibernate.HibernateException;
import org.hibernate.TransactionException;
import org.hibernate.engine.transaction.spi.AbstractTransactionImpl;
import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.engine.transaction.spi.LocalStatus;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.SQLException;
/**
* {@link org.hibernate.Transaction} implementation based on transaction management through a JDBC {@link java.sql.Connection}.
* <p/>
* This the default transaction strategy.
*
* @author Anton van Straaten
* @author Gavin King
* @author Steve Ebersole
*/
public class JdbcTransaction extends AbstractTransactionImpl {
private static final Logger log = LoggerFactory.getLogger( JdbcTransaction.class );
private Connection managedConnection;
private boolean wasInitiallyAutoCommit;
private boolean isDriver;
protected JdbcTransaction(TransactionCoordinator transactionCoordinator) {
super( transactionCoordinator );
}
@Override
protected void doBegin() {
try {
if ( managedConnection != null ) {
throw new TransactionException( "Already have an associated managed connection" );
}
managedConnection = transactionCoordinator().getJdbcCoordinator().getLogicalConnection().getConnection();
wasInitiallyAutoCommit = managedConnection.getAutoCommit();
if ( log.isDebugEnabled() ) {
log.debug( "initial autocommit status: " + wasInitiallyAutoCommit );
}
if ( wasInitiallyAutoCommit ) {
log.debug( "disabling autocommit" );
managedConnection.setAutoCommit( false );
}
}
catch( SQLException e ) {
throw new TransactionException( "JDBC begin transaction failed: ", e );
}
isDriver = transactionCoordinator().takeOwnership();
}
@Override
protected void afterTransactionBegin() {
if ( getTimeout() > 0 ) {
transactionCoordinator().getJdbcCoordinator().setTransactionTimeOut( getTimeout() );
}
transactionCoordinator().sendAfterTransactionBeginNotifications( this );
if ( isDriver ) {
transactionCoordinator().getTransactionContext().afterTransactionBegin( this );
}
}
@Override
protected void beforeTransactionCommit() {
transactionCoordinator().sendBeforeTransactionCompletionNotifications( this );
// basically, if we are the driver of the transaction perform a managed flush prior to
// physically committing the transaction
if ( isDriver && !transactionCoordinator().getTransactionContext().isFlushModeNever() ) {
// if an exception occurs during flush, user must call rollback()
transactionCoordinator().getTransactionContext().managedFlush();
}
if ( isDriver ) {
transactionCoordinator().getTransactionContext().beforeTransactionCompletion( this );
}
}
@Override
protected void doCommit() throws TransactionException {
try {
managedConnection.commit();
log.debug( "committed JDBC Connection" );
}
catch( SQLException e ) {
throw new TransactionException( "unable to commit against JDBC connection", e );
}
finally {
releaseManagedConnection();
}
}
private void releaseManagedConnection() {
try {
if ( wasInitiallyAutoCommit ) {
log.debug( "re-enabling autocommit" );
managedConnection.setAutoCommit( true );
}
managedConnection = null;
}
catch ( Exception e ) {
log.debug( "Could not toggle autocommit", e );
}
}
@Override
protected void afterTransactionCompletion(int status) {
transactionCoordinator().afterTransaction( this, status );
}
@Override
protected void afterAfterCompletion() {
if ( isDriver
&& transactionCoordinator().getTransactionContext().shouldAutoClose()
&& !transactionCoordinator().getTransactionContext().isClosed() ) {
try {
transactionCoordinator().getTransactionContext().managedClose();
}
catch (HibernateException e) {
log.info( "Could not close session; swallowing exception as transaction completed", e );
}
}
}
@Override
protected void beforeTransactionRollBack() {
// nothing to do here
}
@Override
protected void doRollback() throws TransactionException {
try {
managedConnection.rollback();
log.debug( "rolled JDBC Connection" );
}
catch( SQLException e ) {
throw new TransactionException( "unable to rollback against JDBC connection", e );
}
finally {
releaseManagedConnection();
}
}
@Override
public boolean isInitiator() {
return isActive();
}
@Override
public IsolationDelegate createIsolationDelegate() {
return new JdbcIsolationDelegate( transactionCoordinator() );
}
@Override
public JoinStatus getJoinStatus() {
return isActive() ? JoinStatus.JOINED : JoinStatus.NOT_JOINED;
}
@Override
public void markRollbackOnly() {
// nothing to do here
}
@Override
public void join() {
// nothing to do
}
@Override
public void resetJoinStatus() {
// nothing to do
}
@Override
public boolean isActive() throws HibernateException {
return getLocalStatus() == LocalStatus.ACTIVE;
}
}

View File

@ -0,0 +1,71 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007-2011, 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.transaction.internal.jdbc;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionFactory;
/**
* Factory for {@link org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction} instances.
*
* @author Anton van Straaten
* @author Steve Ebersole
*/
public final class JdbcTransactionFactory implements TransactionFactory<JdbcTransaction> {
@Override
public JdbcTransaction createTransaction(TransactionCoordinator transactionCoordinator) {
return new JdbcTransaction( transactionCoordinator );
}
@Override
public boolean canBeDriver() {
return true;
}
@Override
public ConnectionReleaseMode getDefaultReleaseMode() {
return ConnectionReleaseMode.ON_CLOSE;
}
@Override
public boolean compatibleWithJtaSynchronization() {
return false;
}
@Override
public boolean isJoinableJtaTransaction(TransactionCoordinator transactionCoordinator, JdbcTransaction transaction) {
return false;
}
@Override
public JoinStatus getJoinStatus(TransactionCoordinator transactionCoordinator, JdbcTransaction transaction) {
return transaction.getJoinStatus();
}
}

View File

@ -0,0 +1,154 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007-2011, 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.transaction.internal.jta;
import org.hibernate.TransactionException;
import org.hibernate.engine.transaction.spi.AbstractTransactionImpl;
import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
/**
* Implements a transaction strategy for Container Managed Transaction (CMT) scenarios. All work is done in
* the context of the container managed transaction.
* <p/>
* The term 'CMT' is potentially misleading; the pertinent point simply being that the transactions are being
* managed by something other than the Hibernate transaction mechanism.
* <p/>
* Additionally, this strategy does *not* attempt to access or use the {@link javax.transaction.UserTransaction} since
* in the actual case CMT access to the {@link javax.transaction.UserTransaction} is explicitly disallowed. Instead
* we use the JTA {@link javax.transaction.Transaction} object obtained from the {@link TransactionManager}
*
* @author Gavin King
* @author Steve Ebersole
*/
public class CMTTransaction extends AbstractTransactionImpl {
protected CMTTransaction(TransactionCoordinator transactionCoordinator) {
super( transactionCoordinator );
}
protected TransactionManager transactionManager() {
return jtaPlatform().retrieveTransactionManager();
}
private TransactionManager getTransactionManager() {
return transactionManager();
}
@Override
protected void doBegin() {
transactionCoordinator().pulse();
}
@Override
protected void afterTransactionBegin() {
if ( ! transactionCoordinator().isSynchronizationRegistered() ) {
throw new TransactionException("Could not register synchronization for container transaction");
}
transactionCoordinator().sendAfterTransactionBeginNotifications( this );
transactionCoordinator().getTransactionContext().afterTransactionBegin( this );
}
@Override
protected void beforeTransactionCommit() {
boolean flush = ! transactionCoordinator().getTransactionContext().isFlushModeNever() &&
! transactionCoordinator().getTransactionContext().isFlushBeforeCompletionEnabled();
if ( flush ) {
// if an exception occurs during flush, user must call rollback()
transactionCoordinator().getTransactionContext().managedFlush();
}
}
@Override
protected void doCommit() {
// nothing to do
}
@Override
protected void beforeTransactionRollBack() {
// nothing to do
}
@Override
protected void doRollback() {
markRollbackOnly();
}
@Override
protected void afterTransactionCompletion(int status) {
// nothing to do
}
@Override
protected void afterAfterCompletion() {
// nothing to do
}
@Override
public boolean isActive() throws TransactionException {
return JtaStatusHelper.isActive( getTransactionManager() );
}
@Override
public IsolationDelegate createIsolationDelegate() {
return new JtaIsolationDelegate( transactionCoordinator() );
}
@Override
public boolean isInitiator() {
return false; // cannot be
}
@Override
public void markRollbackOnly() {
try {
getTransactionManager().setRollbackOnly();
}
catch ( SystemException se ) {
throw new TransactionException("Could not set transaction to rollback only", se);
}
}
@Override
public void join() {
// todo : implement method body
}
@Override
public void resetJoinStatus() {
// todo : implement method body
}
boolean isJoinable() {
return JtaStatusHelper.isActive( transactionManager() );
}
@Override
public JoinStatus getJoinStatus() {
return isJoinable() ? JoinStatus.JOINED : JoinStatus.NOT_JOINED;
}
}

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,60 +20,64 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.transaction; package org.hibernate.engine.transaction.internal.jta;
import java.util.Properties;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Transaction;
import org.hibernate.TransactionException; import org.hibernate.TransactionException;
import org.hibernate.engine.jdbc.spi.JDBCContext; import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.util.JTAHelper; import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionFactory;
import javax.transaction.SystemException; import javax.transaction.SystemException;
/** /**
* Factory for {@link CMTTransaction} instances. * Factory for Container Managed Transaction (CMT) based transaction facades.
* *
* @author Steve Ebersole
* @author Gavin King * @author Gavin King
*/ */
public class CMTTransactionFactory implements TransactionFactory { public class CMTTransactionFactory implements TransactionFactory<CMTTransaction> {
@Override
public CMTTransaction createTransaction(TransactionCoordinator transactionCoordinator) {
return new CMTTransaction( transactionCoordinator );
}
@Override
public boolean canBeDriver() {
return false;
}
@Override
public ConnectionReleaseMode getDefaultReleaseMode() { public ConnectionReleaseMode getDefaultReleaseMode() {
return ConnectionReleaseMode.AFTER_STATEMENT; return ConnectionReleaseMode.AFTER_STATEMENT;
} }
public void configure(Properties props) throws HibernateException {} @Override
public boolean compatibleWithJtaSynchronization() {
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
throws HibernateException {
return new CMTTransaction(jdbcContext, transactionContext);
}
public boolean isTransactionManagerRequired() {
return true; return true;
} }
public boolean areCallbacksLocalToHibernateTransactions() { @Override
return false; public boolean isJoinableJtaTransaction(TransactionCoordinator transactionCoordinator, CMTTransaction transaction) {
}
public boolean isTransactionInProgress(
JDBCContext jdbcContext,
Context transactionContext,
Transaction transaction) {
try { try {
return JTAHelper.isTransactionInProgress( final int status = transactionCoordinator
transactionContext.getFactory().getTransactionManager().getTransaction() .getTransactionContext()
); .getTransactionEnvironment()
.getJtaPlatform()
.retrieveTransactionManager()
.getStatus();
return JtaStatusHelper.isActive( status );
} }
catch( SystemException se ) { catch( SystemException se ) {
throw new TransactionException( "Unable to check transaction status", se ); throw new TransactionException( "Unable to check transaction status", se );
} }
}
@Override
public JoinStatus getJoinStatus(TransactionCoordinator transactionCoordinator, CMTTransaction transaction) {
return null; // todo : implement method body
} }
} }

View File

@ -0,0 +1,185 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.internal.jta;
import java.sql.Connection;
import java.sql.SQLException;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.jdbc.Work;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
/**
* An isolation delegate for JTA environments.
*
* @author Steve Ebersole
*/
public class JtaIsolationDelegate implements IsolationDelegate {
private static final Logger log = LoggerFactory.getLogger( JtaIsolationDelegate.class );
private final TransactionCoordinator transactionCoordinator;
public JtaIsolationDelegate(TransactionCoordinator transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator;
}
protected TransactionManager transactionManager() {
return transactionCoordinator.getTransactionContext()
.getTransactionEnvironment()
.getJtaPlatform()
.retrieveTransactionManager();
}
protected ConnectionProvider connectionProvider() {
return transactionCoordinator.getTransactionContext()
.getTransactionEnvironment()
.getJdbcServices()
.getConnectionProvider();
}
protected SQLExceptionHelper sqlExceptionHelper() {
return transactionCoordinator.getTransactionContext()
.getTransactionEnvironment()
.getJdbcServices()
.getSqlExceptionHelper();
}
@Override
public void delegateWork(Work work, boolean transacted) throws HibernateException {
TransactionManager transactionManager = transactionManager();
try {
// First we suspend any current JTA transaction
Transaction surroundingTransaction = transactionManager.suspend();
if ( log.isDebugEnabled() ) {
log.debug( "surrounding JTA transaction suspended [" + surroundingTransaction + "]" );
}
boolean hadProblems = false;
try {
// then perform the requested work
if ( transacted ) {
doTheWorkInNewTransaction( work, transactionManager );
}
else {
doTheWorkInNoTransaction( work );
}
}
catch ( HibernateException e ) {
hadProblems = true;
throw e;
}
finally {
try {
transactionManager.resume( surroundingTransaction );
if ( log.isDebugEnabled() ) {
log.debug( "surrounding JTA transaction resumed [" + surroundingTransaction + "]" );
}
}
catch( Throwable t ) {
// if the actually work had an error use that, otherwise error based on t
if ( !hadProblems ) {
//noinspection ThrowFromFinallyBlock
throw new HibernateException( "Unable to resume previously suspended transaction", t );
}
}
}
}
catch ( SystemException e ) {
throw new HibernateException( "Unable to suspend current JTA transaction", e );
}
}
private void doTheWorkInNewTransaction(Work work, TransactionManager transactionManager) {
try {
// start the new isolated transaction
transactionManager.begin();
try {
doTheWork( work );
// if everythign went ok, commit the isolated transaction
transactionManager.commit();
}
catch ( Exception e ) {
try {
transactionManager.rollback();
}
catch ( Exception ignore ) {
log.info( "Unable to rollback isolated transaction on error [" + e + "] : [" + ignore + "]" );
}
}
}
catch ( SystemException e ) {
throw new HibernateException( "Unable to start isolated transaction", e );
}
catch ( NotSupportedException e ) {
throw new HibernateException( "Unable to start isolated transaction", e );
}
}
private void doTheWorkInNoTransaction(Work work) {
doTheWork( work );
}
private void doTheWork(Work work) {
try {
// obtain our isolated connection
Connection connection = connectionProvider().getConnection();
try {
// do the actual work
work.execute( connection );
}
catch ( HibernateException e ) {
throw e;
}
catch ( Exception e ) {
throw new HibernateException( "Unable to perform isolated work", e );
}
finally {
try {
// no matter what, release the connection (handle)
connectionProvider().closeConnection( connection );
}
catch ( Throwable ignore ) {
log.info( "Unable to release isolated connection [" + ignore + "]" );
}
}
}
catch ( SQLException sqle ) {
throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" );
}
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc. * distributed under license by Red Hat Inc.
@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.internal.util.jta; package org.hibernate.engine.transaction.internal.jta;
import javax.transaction.Status; import javax.transaction.Status;
import javax.transaction.SystemException; import javax.transaction.SystemException;
@ -31,7 +31,7 @@ import javax.transaction.UserTransaction;
import org.hibernate.TransactionException; import org.hibernate.TransactionException;
/** /**
* Utility for dealing with JTA statses. * Utility for dealing with JTA statuses.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -49,7 +49,7 @@ public class JtaStatusHelper {
try { try {
final int status = userTransaction.getStatus(); final int status = userTransaction.getStatus();
if ( status == Status.STATUS_UNKNOWN ) { if ( status == Status.STATUS_UNKNOWN ) {
throw new TransactionException( "UserTransaction reported transaction status as unknwon" ); throw new TransactionException( "UserTransaction reported transaction status as unknown" );
} }
return status; return status;
} }
@ -97,7 +97,7 @@ public class JtaStatusHelper {
* *
* @param userTransaction The {@link UserTransaction} whose status is to be checked * @param userTransaction The {@link UserTransaction} whose status is to be checked
* *
* @return True if the transactiion is active; false otherwise. * @return True if the transaction is active; false otherwise.
*/ */
public static boolean isActive(UserTransaction userTransaction) { public static boolean isActive(UserTransaction userTransaction) {
final int status = getStatus( userTransaction ); final int status = getStatus( userTransaction );
@ -109,7 +109,7 @@ public class JtaStatusHelper {
* *
* @param transactionManager The {@link TransactionManager} whose status is to be checked * @param transactionManager The {@link TransactionManager} whose status is to be checked
* *
* @return True if the transactiion is active; false otherwise. * @return True if the transaction is active; false otherwise.
*/ */
public static boolean isActive(TransactionManager transactionManager) { public static boolean isActive(TransactionManager transactionManager) {
return isActive( getStatus( transactionManager ) ); return isActive( getStatus( transactionManager ) );
@ -133,7 +133,7 @@ public class JtaStatusHelper {
* *
* @param userTransaction The {@link UserTransaction} whose status is to be checked * @param userTransaction The {@link UserTransaction} whose status is to be checked
* *
* @return True if the transactiion indicates roll back; false otherwise. * @return True if the transaction indicates roll back; false otherwise.
*/ */
public static boolean isRollback(UserTransaction userTransaction) { public static boolean isRollback(UserTransaction userTransaction) {
return isRollback( getStatus( userTransaction ) ); return isRollback( getStatus( userTransaction ) );
@ -144,7 +144,7 @@ public class JtaStatusHelper {
* *
* @param transactionManager The {@link TransactionManager} whose status is to be checked * @param transactionManager The {@link TransactionManager} whose status is to be checked
* *
* @return True if the transactiion indicates roll back; false otherwise. * @return True if the transaction indicates roll back; false otherwise.
*/ */
public static boolean isRollback(TransactionManager transactionManager) { public static boolean isRollback(TransactionManager transactionManager) {
return isRollback( getStatus( transactionManager ) ); return isRollback( getStatus( transactionManager ) );
@ -158,9 +158,7 @@ public class JtaStatusHelper {
* @return True if the code indicates a roll back; false otherwise. * @return True if the code indicates a roll back; false otherwise.
*/ */
public static boolean isCommitted(int status) { public static boolean isCommitted(int status) {
return status == Status.STATUS_MARKED_ROLLBACK || return status == Status.STATUS_COMMITTED;
status == Status.STATUS_ROLLING_BACK ||
status == Status.STATUS_ROLLEDBACK;
} }
/** /**
@ -168,7 +166,7 @@ public class JtaStatusHelper {
* *
* @param userTransaction The {@link UserTransaction} whose status is to be checked * @param userTransaction The {@link UserTransaction} whose status is to be checked
* *
* @return True if the transactiion indicates commit; false otherwise. * @return True if the transaction indicates commit; false otherwise.
*/ */
public static boolean isCommitted(UserTransaction userTransaction) { public static boolean isCommitted(UserTransaction userTransaction) {
return isCommitted( getStatus( userTransaction ) ); return isCommitted( getStatus( userTransaction ) );
@ -179,7 +177,7 @@ public class JtaStatusHelper {
* *
* @param transactionManager The {@link TransactionManager} whose status is to be checked * @param transactionManager The {@link TransactionManager} whose status is to be checked
* *
* @return True if the transactiion indicates commit; false otherwise. * @return True if the transaction indicates commit; false otherwise.
*/ */
public static boolean isCommitted(TransactionManager transactionManager) { public static boolean isCommitted(TransactionManager transactionManager) {
return isCommitted( getStatus( transactionManager ) ); return isCommitted( getStatus( transactionManager ) );
@ -192,6 +190,7 @@ public class JtaStatusHelper {
* *
* @return True if the code indicates a roll back; false otherwise. * @return True if the code indicates a roll back; false otherwise.
*/ */
@SuppressWarnings( {"UnusedDeclaration"})
public static boolean isMarkedForRollback(int status) { public static boolean isMarkedForRollback(int status) {
return status == Status.STATUS_MARKED_ROLLBACK; return status == Status.STATUS_MARKED_ROLLBACK;
} }

View File

@ -0,0 +1,276 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007-2011, 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.transaction.internal.jta;
import org.hibernate.HibernateException;
import org.hibernate.TransactionException;
import org.hibernate.engine.transaction.spi.AbstractTransactionImpl;
import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.engine.transaction.spi.LocalStatus;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
/**
* Implements a transaction strategy based on transaction management through a JTA {@link UserTransaction}.
*
* @author Gavin King
* @author Steve Ebersole
* @author Les Hazlewood
*/
public class JtaTransaction extends AbstractTransactionImpl {
private static final Logger log = LoggerFactory.getLogger( JtaTransaction.class );
private UserTransaction userTransaction;
private boolean isInitiator;
private boolean isDriver;
protected JtaTransaction(TransactionCoordinator transactionCoordinator) {
super( transactionCoordinator );
}
@SuppressWarnings( {"UnusedDeclaration"})
public UserTransaction getUserTransaction() {
return userTransaction;
}
@Override
protected void doBegin() {
log.debug( "begin" );
userTransaction = jtaPlatform().retrieveUserTransaction();
if ( userTransaction == null ) {
throw new TransactionException( "Unable to locate JTA UserTransaction" );
}
try {
if ( userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION ) {
userTransaction.begin();
isInitiator = true;
log.debug( "Began a new JTA transaction" );
}
}
catch ( Exception e ) {
throw new TransactionException( "JTA transaction begin failed", e );
}
}
@Override
protected void afterTransactionBegin() {
transactionCoordinator().pulse();
if ( !transactionCoordinator().isSynchronizationRegistered() ) {
isDriver = transactionCoordinator().takeOwnership();
}
applyTimeout();
transactionCoordinator().sendAfterTransactionBeginNotifications( this );
transactionCoordinator().getTransactionContext().afterTransactionBegin( this );
}
private void applyTimeout() {
if ( getTimeout() > 0 ) {
if ( userTransaction != null ) {
try {
userTransaction.setTransactionTimeout( getTimeout() );
}
catch ( SystemException e ) {
throw new TransactionException( "Unable to apply requested transaction timeout", e );
}
}
else {
log.debug( "Unable to apply requested transaction timeout; no UserTransaction. Will try later" );
}
}
}
@Override
protected void beforeTransactionCommit() {
transactionCoordinator().sendBeforeTransactionCompletionNotifications( this );
final boolean flush = ! transactionCoordinator().getTransactionContext().isFlushModeNever() &&
( isDriver || ! transactionCoordinator().getTransactionContext().isFlushBeforeCompletionEnabled() );
if ( flush ) {
// if an exception occurs during flush, user must call rollback()
transactionCoordinator().getTransactionContext().managedFlush();
}
if ( isDriver && isInitiator ) {
transactionCoordinator().getTransactionContext().beforeTransactionCompletion( this );
}
closeIfRequired();
}
private void closeIfRequired() throws HibernateException {
final boolean close = isDriver &&
transactionCoordinator().getTransactionContext().shouldAutoClose() &&
! transactionCoordinator().getTransactionContext().isClosed();
if ( close ) {
transactionCoordinator().getTransactionContext().managedClose();
}
}
@Override
protected void doCommit() {
try {
if ( isInitiator ) {
userTransaction.commit();
log.debug( "Committed JTA UserTransaction" );
}
}
catch ( Exception e ) {
throw new TransactionException( "JTA commit failed: ", e );
}
finally {
isInitiator = false;
}
}
@Override
protected void afterTransactionCompletion(int status) {
// nothing to do
}
@Override
protected void afterAfterCompletion() {
// this method is a noop if there is a Synchronization!
if ( isDriver ) {
if ( !isInitiator ) {
log.warn( "You should set hibernate.transaction.manager_lookup_class if cache is enabled" );
}
try {
transactionCoordinator().afterTransaction( this, userTransaction.getStatus() );
}
catch (SystemException e) {
throw new TransactionException( "Unable to determine UserTransaction status", e );
}
}
}
@Override
protected void beforeTransactionRollBack() {
// nothing to do
}
@Override
protected void doRollback() {
try {
if ( isInitiator ) {
// failed commits automatically rollback the transaction per JTA spec
if ( getLocalStatus() != LocalStatus.FAILED_COMMIT ) {
userTransaction.rollback();
log.debug( "Rolled back JTA UserTransaction" );
}
}
else {
markRollbackOnly();
}
}
catch ( Exception e ) {
throw new TransactionException( "JTA rollback failed", e );
}
}
@Override
public void markRollbackOnly() {
log.trace( "Marking transaction for rollback only" );
try {
userTransaction.setRollbackOnly();
log.debug( "set JTA UserTransaction to rollback only" );
}
catch (SystemException e) {
log.debug( "Unable to mark transaction for rollback only", e );
}
}
@Override
public IsolationDelegate createIsolationDelegate() {
return new JtaIsolationDelegate( transactionCoordinator() );
}
@Override
public boolean isInitiator() {
return isInitiator;
}
@Override
public boolean isActive() throws HibernateException {
if ( getLocalStatus() != LocalStatus.ACTIVE ) {
return false;
}
final int status;
try {
status = userTransaction.getStatus();
}
catch ( SystemException se ) {
throw new TransactionException( "Could not determine transaction status: ", se );
}
return JtaStatusHelper.isActive( status );
}
@Override
public void setTimeout(int seconds) {
super.setTimeout( seconds );
applyTimeout();
}
@Override
public void join() {
}
@Override
public void resetJoinStatus() {
}
@Override
public JoinStatus getJoinStatus() {
// if we already have the UserTransaction cached locally, use it to avoid JNDI look ups
if ( this.userTransaction != null ) {
return JtaStatusHelper.isActive( this.userTransaction ) ? JoinStatus.JOINED : JoinStatus.NOT_JOINED;
}
// Otherwise, try to use the TransactionManager since it is generally cached
TransactionManager transactionManager = jtaPlatform().retrieveTransactionManager();
if ( transactionManager != null ) {
return JtaStatusHelper.isActive( transactionManager ) ? JoinStatus.JOINED : JoinStatus.NOT_JOINED;
}
// Finally, look up the UserTransaction
UserTransaction userTransaction = jtaPlatform().retrieveUserTransaction();
return userTransaction != null && JtaStatusHelper.isActive( userTransaction )
? JoinStatus.JOINED
: JoinStatus.NOT_JOINED;
}
}

View File

@ -0,0 +1,109 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007-2011, 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.transaction.internal.jta;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.TransactionException;
import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionFactory;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.util.JTAHelper;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
/**
* Factory for {@link JtaTransaction} instances.
*
* @author Gavin King
* @author Steve Ebersole
* @author Les Hazlewood
*/
public class JtaTransactionFactory implements TransactionFactory<JtaTransaction> {
@Override
public JtaTransaction createTransaction(TransactionCoordinator transactionCoordinator) {
return new JtaTransaction( transactionCoordinator );
}
@Override
public boolean canBeDriver() {
return true;
}
@Override
public ConnectionReleaseMode getDefaultReleaseMode() {
return ConnectionReleaseMode.AFTER_STATEMENT;
}
@Override
public boolean compatibleWithJtaSynchronization() {
return true;
}
@Override
public boolean isJoinableJtaTransaction(TransactionCoordinator transactionCoordinator, JtaTransaction transaction) {
try {
// Essentially:
// 1) If we have a local (Hibernate) transaction in progress
// and it already has the UserTransaction cached, use that
// UserTransaction to determine the status.
// 2) If a transaction manager has been located, use
// that transaction manager to determine the status.
// 3) Finally, as the last resort, try to lookup the
// UserTransaction via JNDI and use that to determine the
// status.
if ( transaction != null ) {
UserTransaction ut = transaction.getUserTransaction();
if ( ut != null ) {
return JTAHelper.isInProgress( ut.getStatus() );
}
}
final JtaPlatform jtaPlatform = transactionCoordinator
.getTransactionContext()
.getTransactionEnvironment()
.getJtaPlatform();
if ( jtaPlatform == null ) {
throw new TransactionException( "Unable to check transaction status" );
}
if ( jtaPlatform.retrieveTransactionManager() != null ) {
return JtaStatusHelper.isActive( jtaPlatform.retrieveTransactionManager().getStatus() );
}
else {
final UserTransaction ut = jtaPlatform.retrieveUserTransaction();
return ut != null && JTAHelper.isInProgress( ut.getStatus() );
}
}
catch ( SystemException se ) {
throw new TransactionException( "Unable to check transaction status", se );
}
}
@Override
public JoinStatus getJoinStatus(TransactionCoordinator transactionCoordinator, JtaTransaction transaction) {
return null; // todo : implement method body
}
}

View File

@ -0,0 +1,237 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
import org.hibernate.HibernateException;
import org.hibernate.TransactionException;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.transaction.Status;
import javax.transaction.Synchronization;
/**
* Abstract support for creating {@link TransactionImplementor transaction} implementations
*
* @author Steve Ebersole
*/
public abstract class AbstractTransactionImpl implements TransactionImplementor {
private static final Logger log = LoggerFactory.getLogger( AbstractTransactionImpl.class );
private final TransactionCoordinator transactionCoordinator;
private boolean valid = true;
private LocalStatus localStatus = LocalStatus.NOT_ACTIVE;
private int timeout = -1;
protected AbstractTransactionImpl(TransactionCoordinator transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator;
}
@Override
public void invalidate() {
valid = false;
}
/**
* Perform the actual steps of beginning a transaction according to the strategy.
*
* @throws org.hibernate.TransactionException Indicates a problem beginning the transaction
*/
protected abstract void doBegin();
/**
* Perform the actual steps of committing a transaction according to the strategy.
*
* @throws org.hibernate.TransactionException Indicates a problem committing the transaction
*/
protected abstract void doCommit();
/**
* Perform the actual steps of rolling back a transaction according to the strategy.
*
* @throws org.hibernate.TransactionException Indicates a problem rolling back the transaction
*/
protected abstract void doRollback();
protected abstract void afterTransactionBegin();
protected abstract void beforeTransactionCommit();
protected abstract void beforeTransactionRollBack();
protected abstract void afterTransactionCompletion(int status);
protected abstract void afterAfterCompletion();
/**
* Provide subclasses with access to the transaction coordinator.
*
* @return This transaction's context.
*/
protected TransactionCoordinator transactionCoordinator() {
return transactionCoordinator;
}
/**
* Provide subclasses with convenient access to the configured {@link JtaPlatform}
*
* @return The {@link org.hibernate.service.jta.platform.spi.JtaPlatform}
*/
protected JtaPlatform jtaPlatform() {
return transactionCoordinator().getTransactionContext().getTransactionEnvironment().getJtaPlatform();
}
@Override
public void registerSynchronization(Synchronization synchronization) {
transactionCoordinator().getSynchronizationRegistry().registerSynchronization( synchronization );
}
@Override
public LocalStatus getLocalStatus() {
return localStatus;
}
@Override
public boolean isActive() {
return localStatus == LocalStatus.ACTIVE && doExtendedActiveCheck();
}
@Override
public boolean wasCommitted() {
return localStatus == LocalStatus.COMMITTED;
}
@Override
public boolean wasRolledBack() throws HibernateException {
return localStatus == LocalStatus.ROLLED_BACK;
}
/**
* Active has been checked against local state. Perform any needed checks against resource transactions.
*
* @return {@code true} if the extended active check checks out as well; false otherwise.
*/
protected boolean doExtendedActiveCheck() {
return true;
}
@Override
public void begin() throws HibernateException {
if ( ! valid ) {
throw new TransactionException( "Transaction instance is no longer valid" );
}
if ( localStatus == LocalStatus.ACTIVE ) {
throw new TransactionException( "nested transactions not supported" );
}
if ( localStatus != LocalStatus.NOT_ACTIVE ) {
throw new TransactionException( "reuse of Transaction instances not supported" );
}
log.debug( "begin" );
doBegin();
localStatus = LocalStatus.ACTIVE;
afterTransactionBegin();
}
@Override
public void commit() throws HibernateException {
if ( localStatus != LocalStatus.ACTIVE ) {
throw new TransactionException( "Transaction not successfully started" );
}
log.debug( "committing" );
beforeTransactionCommit();
try {
doCommit();
localStatus = LocalStatus.COMMITTED;
afterTransactionCompletion( Status.STATUS_COMMITTED );
}
catch ( Exception e ) {
localStatus = LocalStatus.FAILED_COMMIT;
afterTransactionCompletion( Status.STATUS_UNKNOWN );
throw new TransactionException( "commit failed", e );
}
finally {
invalidate();
afterAfterCompletion();
}
}
protected boolean allowFailedCommitToPhysicallyRollback() {
return false;
}
@Override
public void rollback() throws HibernateException {
if ( localStatus != LocalStatus.ACTIVE && localStatus != LocalStatus.FAILED_COMMIT ) {
throw new TransactionException( "Transaction not successfully started" );
}
log.debug( "rolling back" );
beforeTransactionRollBack();
if ( localStatus != LocalStatus.FAILED_COMMIT || allowFailedCommitToPhysicallyRollback() ) {
try {
doRollback();
localStatus = LocalStatus.ROLLED_BACK;
afterTransactionCompletion( Status.STATUS_ROLLEDBACK );
}
catch ( Exception e ) {
afterTransactionCompletion( Status.STATUS_UNKNOWN );
throw new TransactionException( "rollback failed", e );
}
finally {
invalidate();
afterAfterCompletion();
}
}
}
@Override
public void setTimeout(int seconds) {
timeout = seconds;
}
@Override
public int getTimeout() {
return timeout;
}
@Override
public void resetJoinStatus() {
// generally speaking this is no-op
}
@Override
public void join() {
// generally speaking this is no-op
}
}

View File

@ -0,0 +1,44 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
import org.hibernate.HibernateException;
import org.hibernate.jdbc.Work;
/**
* Contract for performing work in a manner that isolates it from any current transaction.
*
* @author Steve Ebersole
*/
public interface IsolationDelegate {
/**
* Perform the given work in isolation from current transaction.
*
* @param work The work to be performed.
* @param transacted Should the work itself be done in a (isolated) transaction?
*
* @throws HibernateException Indicates a problem performing the work.
*/
public void delegateWork(Work work, boolean transacted) throws HibernateException;
}

View File

@ -1,7 +1,7 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc. * distributed under license by Red Hat Inc.
@ -21,15 +21,16 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.transaction.synchronization; package org.hibernate.engine.transaction.spi;
import org.hibernate.transaction.TransactionFactory;
/** /**
* TODO : javadoc * See the JPA notion of joining a transaction for details.
* *
* @author Emmanuel Bernard
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface AfterCompletionAction { public enum JoinStatus {
public void doAction(TransactionFactory.Context ctx, int status); NOT_JOINED,
MARKED_FOR_JOINED,
JOINED
} }

View File

@ -0,0 +1,52 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
/**
* Enumeration of statuses in which a local transaction facade ({@link org.hibernate.Transaction}) might be.
*
* @author Steve Ebersole
*/
public enum LocalStatus {
/**
* The local transaction has not yet been begun
*/
NOT_ACTIVE,
/**
* The local transaction has been begun, but not yet completed.
*/
ACTIVE,
/**
* The local transaction has been competed successfully.
*/
COMMITTED,
/**
* The local transaction has been rolled back.
*/
ROLLED_BACK,
/**
* The local transaction attempted to commit, but failed.
*/
FAILED_COMMIT
}

View File

@ -0,0 +1,57 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
import javax.transaction.Synchronization;
import java.io.Serializable;
/**
* Manages a registry of {@link Synchronization Synchronizations}.
*
* @author Steve Ebersole
*/
public interface SynchronizationRegistry extends Serializable {
/**
* Register a user {@link Synchronization} callback for this transaction.
*
* @param synchronization The synchronization callback to register.
*
* @throws org.hibernate.HibernateException
*/
public void registerSynchronization(Synchronization synchronization);
/**
* Delegate {@link Synchronization#beforeCompletion} calls to the {@link #registerSynchronization registered}
* {@link Synchronization Synchronizations}
*/
void notifySynchronizationsBeforeTransactionCompletion();
/**
* Delegate {@link Synchronization#afterCompletion} calls to {@link #registerSynchronization registered}
* {@link Synchronization Synchronizations}
*
* @param status The transaction status (if known) per {@link javax.transaction.Status}
*/
void notifySynchronizationsAfterTransactionCompletion(int status);
}

View File

@ -0,0 +1,105 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
import org.hibernate.ConnectionReleaseMode;
import java.io.Serializable;
/**
* Access to services needed in the context of processing transaction requests.
* <p/>
* The context is roughly speaking equivalent to the Hibernate session, as opposed to the {@link TransactionEnvironment}
* which is roughly equivalent to the Hibernate session factory
*
* @author Steve Ebersole
*/
public interface TransactionContext extends Serializable {
/**
* Obtain the {@link TransactionEnvironment} associated with this context.
*
* @return The transaction environment.
*/
public TransactionEnvironment getTransactionEnvironment();
/**
* Get the mode for releasing JDBC connection in effect for ths context.
*
* @return The connection release mode.
*/
public ConnectionReleaseMode getConnectionReleaseMode();
/**
* Should session automatically be closed after transaction completion in this context?
*
* @return {@literal true}/{@literal false} appropriately.
*/
public boolean isAutoCloseSessionEnabled();
/**
* Is this context already closed?
*
* @return {@literal true}/{@literal false} appropriately.
*/
public boolean isClosed();
/**
* Should flushes only happen manually for this context?
*
* @return {@literal true}/{@literal false} appropriately.
*/
public boolean isFlushModeNever();
/**
* Should before transaction completion processing perform a flush when initiated from JTA synchronization for this
* context?
*
* @return {@literal true}/{@literal false} appropriately.
*/
public boolean isFlushBeforeCompletionEnabled();
/**
* Perform a managed flush.
*/
public void managedFlush();
/**
* Should JTA synchronization processing perform a automatic close (call to {@link #managedClose} for this
* context?
*
* @return {@literal true}/{@literal false} appropriately.
*/
public boolean shouldAutoClose();
/**
* Perform a managed close.
*/
public void managedClose();
public void afterTransactionBegin(TransactionImplementor hibernateTransaction);
public void beforeTransactionCompletion(TransactionImplementor hibernateTransaction);
public void afterTransactionCompletion(TransactionImplementor hibernateTransaction, boolean successful);
}

View File

@ -0,0 +1,139 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
import java.io.Serializable;
import java.sql.Connection;
/**
* Acts as the coordinator between the Hibernate engine and physical transactions.
*
* @author Steve Ebersole
*/
public interface TransactionCoordinator extends Serializable {
/**
* Retrieves the context in which this coordinator operates.
*
* @return The context of the coordinator
*/
public TransactionContext getTransactionContext();
/**
* Retrieves the JDBC coordinator currently operating within this transaction coordinator.
*
* @return The JDBC coordinator.
*/
public JdbcCoordinator getJdbcCoordinator();
/**
* Get the Hibernate transaction facade object currently associated with this coordinator.
*
* @return The current Hibernate transaction.
*/
public TransactionImplementor getTransaction();
/**
* Obtain the {@link javax.transaction.Synchronization} registry associated with this coordinator.
*
* @return The registry
*/
public SynchronizationRegistry getSynchronizationRegistry();
/**
* Adds an observer to the coordinator.
* <p/>
* Unlike synchronizations added to the {@link #getSynchronizationRegistry() registry}, observers are not to be
* cleared on transaction completion.
*
* @param observer The observer to add.
*/
public void addObserver(TransactionObserver observer);
/**
* Can we join to the underlying transaction?
*
* @return {@literal true} if the underlying transaction can be joined or is already joined; {@literal false}
* otherwise.
*
* @see TransactionFactory#isJoinableJtaTransaction(TransactionCoordinator, TransactionImplementor)
*/
public boolean isTransactionJoinable();
/**
* Is the underlying transaction already joined?
*
* @return {@literal true} if the underlying transaction is already joined; {@literal false} otherwise.
*
* @see TransactionFactory#getJoinStatus(TransactionCoordinator, TransactionImplementor)
*/
public boolean isTransactionJoined();
/**
* Reset the transaction's join status.
*/
public void resetJoinStatus();
/**
* Are we "in" an active and joined transaction
*
* @return {@literal true} if there is currently a transaction in progress; {@literal false} otherwise.
*/
public boolean isTransactionInProgress();
/**
* Attempts to register JTA synchronization if possible and needed.
*/
public void pulse();
/**
* Close the transaction context, returning any user supplied connection from the underlying JDBC coordinator.
*
* @return The user supplied connection (if one).
*/
public Connection close();
/**
* Performs actions needed after execution of a non-transactional query.
*
* @param success Was the query successfully performed
*/
public void afterNonTransactionalQuery(boolean success);
public void setRollbackOnly();
public SynchronizationCallbackCoordinator getSynchronizationCallbackCoordinator();
public boolean isSynchronizationRegistered();
public boolean takeOwnership();
public void afterTransaction(TransactionImplementor hibernateTransaction, int status);
public void sendAfterTransactionBeginNotifications(TransactionImplementor hibernateTransaction);
public void sendBeforeTransactionCompletionNotifications(TransactionImplementor hibernateTransaction);
public void sendAfterTransactionCompletionNotifications(TransactionImplementor hibernateTransaction, int status);
}

View File

@ -0,0 +1,63 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
/**
* Provides access to transactional services.
*
* @author Steve Ebersole
*/
public interface TransactionEnvironment {
/**
* Retrieve the session factory for this environment.
*
* @return The session factory
*/
public SessionFactoryImplementor getSessionFactory();
/**
* Retrieve the JDBC services for this environment.
*
* @return The JDBC services
*/
public JdbcServices getJdbcServices();
/**
* Retrieve the JTA platform for this environment.
*
* @return The JTA platform
*/
public JtaPlatform getJtaPlatform();
/**
* Retrieve the transaction factory for this environment.
*
* @return The transaction factory
*/
public TransactionFactory getTransactionFactory();
}

View File

@ -0,0 +1,93 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.service.spi.Service;
/**
* Contract for transaction creation, as well as providing metadata and contextual information about that creation.
*
* @author Steve Ebersole
*/
public interface TransactionFactory<T extends TransactionImplementor> extends Service {
/**
* Construct a transaction instance compatible with this strategy.
*
* @param coordinator The coordinator for this transaction
*
* @return The appropriate transaction instance.
*
* @throws org.hibernate.HibernateException Indicates a problem constructing the transaction.
*/
public T createTransaction(TransactionCoordinator coordinator);
/**
* Can the transactions created from this strategy act as the driver? In other words can the user actually manage
* transactions with this strategy?
*
* @return {@literal true} if the transaction strategy represented by this factory can act as the driver callback;
* {@literal false} otherwise.
*/
public boolean canBeDriver();
/**
* Should we attempt to register JTA transaction {@link javax.transaction.Synchronization synchronizations}.
* <p/>
* In other words, is this strategy JTA-based?
*
* @return {@literal true} if the transaction strategy represented by this factory is compatible with registering
* {@link javax.transaction.Synchronization synchronizations}; {@literal false} otherwise.
*/
public boolean compatibleWithJtaSynchronization();
/**
* Can the underlying transaction represented by the passed Hibernate {@link TransactionImplementor} be joined?
*
* @param transactionCoordinator The transaction coordinator
* @param transaction The current Hibernate transaction
*
* @return {@literal true} is the transaction can be joined; {@literal false} otherwise.
*/
public boolean isJoinableJtaTransaction(TransactionCoordinator transactionCoordinator, T transaction);
/**
* Retrieve the current join status of the Hibernate transaction
*
* @param transactionCoordinator The transaction coordinator
* @param transaction The current Hibernate transaction
*
* @return The join status.
*/
public JoinStatus getJoinStatus(TransactionCoordinator transactionCoordinator, T transaction);
/**
* Get the default connection release mode.
*
* @return The default release mode associated with this strategy
*/
public ConnectionReleaseMode getDefaultReleaseMode();
}

View File

@ -0,0 +1,67 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
import org.hibernate.Transaction;
/**
* Additional contract for implementors of the Hibernate {@link Transaction} API.
*
* @author Steve Ebersole
*/
public interface TransactionImplementor extends Transaction {
/**
* Retrieve an isolation delegate appropriate for this transaction strategy.
*
* @return An isolation delegate.
*/
public IsolationDelegate createIsolationDelegate();
/**
* Get the current state of this transaction's join status.
*
* @return The current join status
*/
public JoinStatus getJoinStatus();
/**
* Perform a join to the underlying transaction
*/
public void join();
/**
* Reset this transaction's join status.
*/
public void resetJoinStatus();
/**
* Make a best effort to mark the underlying transaction for rollback only.
*/
public void markRollbackOnly();
/**
* Called after completion of the underlying transaction to signify the facade is no longer valid.
*/
public void invalidate();
}

View File

@ -0,0 +1,57 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.spi;
/**
* Observer of internal transaction events.
*
* @author Steve Ebersole
*/
public interface TransactionObserver {
/**
* Callback for processing the beginning of a transaction.
*
* Do not rely on this being called as the transaction mat be started in a manner other than through the
* {@link org.hibernate.Transaction} API.
*
* @param transaction The Hibernate transaction
*/
public void afterBegin(TransactionImplementor transaction);
/**
* Callback for processing the initial phase of transaction completion.
*
* @param transaction The Hibernate transaction
*/
public void beforeCompletion(TransactionImplementor transaction);
/**
* Callback for processing the last phase of transaction completion.
*
* @param successful Was the transaction successful?
* @param transaction The Hibernate transaction
*/
public void afterCompletion(boolean successful, TransactionImplementor transaction);
}

View File

@ -1,7 +1,7 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc. * distributed under license by Red Hat Inc.
@ -21,26 +21,26 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.transaction.synchronization; package org.hibernate.engine.transaction.synchronization.internal;
import javax.transaction.Synchronization;
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.transaction.Synchronization;
/** /**
* The {@link Synchronization} implementation Hibernate registers with the JTA {@link javax.transaction.Transaction} * The JTA {@link javax.transaction.Synchronization} Hibernate registers when needed for JTA callbacks
* *
* @author Gavin King
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class HibernateSynchronizationImpl implements Synchronization { public class RegisteredSynchronization implements Synchronization {
private static final Logger log = LoggerFactory.getLogger( HibernateSynchronizationImpl.class ); private static final Logger log = LoggerFactory.getLogger( RegisteredSynchronization.class );
private final CallbackCoordinator coordinator; private final SynchronizationCallbackCoordinator synchronizationCallbackCoordinator;
public HibernateSynchronizationImpl(CallbackCoordinator coordinator) { public RegisteredSynchronization(SynchronizationCallbackCoordinator synchronizationCallbackCoordinator) {
this.coordinator = coordinator; this.synchronizationCallbackCoordinator = synchronizationCallbackCoordinator;
} }
/** /**
@ -48,7 +48,7 @@ public class HibernateSynchronizationImpl implements Synchronization {
*/ */
public void beforeCompletion() { public void beforeCompletion() {
log.trace( "JTA sync : beforeCompletion()" ); log.trace( "JTA sync : beforeCompletion()" );
coordinator.beforeCompletion(); synchronizationCallbackCoordinator.beforeCompletion();
} }
/** /**
@ -56,6 +56,6 @@ public class HibernateSynchronizationImpl implements Synchronization {
*/ */
public void afterCompletion(int status) { public void afterCompletion(int status) {
log.trace( "JTA sync : afterCompletion({})", status ); log.trace( "JTA sync : afterCompletion({})", status );
coordinator.afterCompletion( status ); synchronizationCallbackCoordinator.afterCompletion( status );
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc. * distributed under license by Red Hat Inc.
@ -21,75 +21,57 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.transaction.synchronization; package org.hibernate.engine.transaction.synchronization.internal;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import org.hibernate.TransactionException;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.synchronization.spi.AfterCompletionAction;
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
import org.hibernate.engine.transaction.synchronization.spi.ExceptionMapper;
import org.hibernate.engine.transaction.synchronization.spi.ManagedFlushChecker;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.hibernate.TransactionException; import javax.transaction.SystemException;
import org.hibernate.engine.jdbc.spi.JDBCContext;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.util.JTAHelper;
/** /**
* Manages callbacks from the {@link javax.transaction.Synchronization} registered by Hibernate. * Manages callbacks from the {@link javax.transaction.Synchronization} registered by Hibernate.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class CallbackCoordinator { public class SynchronizationCallbackCoordinatorImpl implements SynchronizationCallbackCoordinator {
private static final Logger log = LoggerFactory.getLogger( CallbackCoordinator.class ); private static final Logger log = LoggerFactory.getLogger( SynchronizationCallbackCoordinatorImpl.class );
private final TransactionFactory.Context ctx; private final TransactionCoordinator transactionCoordinator;
private JDBCContext jdbcContext;
private final Transaction jtaTransaction;
private final org.hibernate.Transaction hibernateTransaction;
private BeforeCompletionManagedFlushChecker beforeCompletionManagedFlushChecker; private ManagedFlushChecker managedFlushChecker;
private AfterCompletionAction afterCompletionAction; private AfterCompletionAction afterCompletionAction;
private ExceptionMapper exceptionMapper; private ExceptionMapper exceptionMapper;
public CallbackCoordinator( public SynchronizationCallbackCoordinatorImpl(TransactionCoordinator transactionCoordinator) {
TransactionFactory.Context ctx, this.transactionCoordinator = transactionCoordinator;
JDBCContext jdbcContext,
Transaction jtaTransaction,
org.hibernate.Transaction hibernateTransaction) {
this.ctx = ctx;
this.jdbcContext = jdbcContext;
this.jtaTransaction = jtaTransaction;
this.hibernateTransaction = hibernateTransaction;
reset(); reset();
} }
public void reset() { public void reset() {
beforeCompletionManagedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER; managedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER;
exceptionMapper = STANDARD_EXCEPTION_MAPPER; exceptionMapper = STANDARD_EXCEPTION_MAPPER;
afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION; afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION;
} }
public BeforeCompletionManagedFlushChecker getBeforeCompletionManagedFlushChecker() { @Override
return beforeCompletionManagedFlushChecker; public void setManagedFlushChecker(ManagedFlushChecker managedFlushChecker) {
} this.managedFlushChecker = managedFlushChecker;
public void setBeforeCompletionManagedFlushChecker(BeforeCompletionManagedFlushChecker beforeCompletionManagedFlushChecker) {
this.beforeCompletionManagedFlushChecker = beforeCompletionManagedFlushChecker;
}
public ExceptionMapper getExceptionMapper() {
return exceptionMapper;
} }
@Override
public void setExceptionMapper(ExceptionMapper exceptionMapper) { public void setExceptionMapper(ExceptionMapper exceptionMapper) {
this.exceptionMapper = exceptionMapper; this.exceptionMapper = exceptionMapper;
} }
public AfterCompletionAction getAfterCompletionAction() { @Override
return afterCompletionAction;
}
public void setAfterCompletionAction(AfterCompletionAction afterCompletionAction) { public void setAfterCompletionAction(AfterCompletionAction afterCompletionAction) {
this.afterCompletionAction = afterCompletionAction; this.afterCompletionAction = afterCompletionAction;
} }
@ -102,7 +84,12 @@ public class CallbackCoordinator {
boolean flush; boolean flush;
try { try {
flush = beforeCompletionManagedFlushChecker.shouldDoManagedFlush( ctx, jtaTransaction ); final int status = transactionCoordinator
.getTransactionContext()
.getTransactionEnvironment()
.getJtaPlatform()
.getCurrentStatus();
flush = managedFlushChecker.shouldDoManagedFlush( transactionCoordinator, status );
} }
catch ( SystemException se ) { catch ( SystemException se ) {
setRollbackOnly(); setRollbackOnly();
@ -112,7 +99,7 @@ public class CallbackCoordinator {
try { try {
if ( flush ) { if ( flush ) {
log.trace( "automatically flushing session" ); log.trace( "automatically flushing session" );
ctx.managedFlush(); transactionCoordinator.getTransactionContext().managedFlush();
} }
} }
catch ( RuntimeException re ) { catch ( RuntimeException re ) {
@ -120,48 +107,41 @@ public class CallbackCoordinator {
throw exceptionMapper.mapManagedFlushFailure( "error during managed flush", re ); throw exceptionMapper.mapManagedFlushFailure( "error during managed flush", re );
} }
finally { finally {
jdbcContext.beforeTransactionCompletion( hibernateTransaction ); transactionCoordinator.sendBeforeTransactionCompletionNotifications( null );
transactionCoordinator.getTransactionContext().beforeTransactionCompletion( null );
} }
} }
private void setRollbackOnly() { private void setRollbackOnly() {
try { transactionCoordinator.setRollbackOnly();
jtaTransaction.setRollbackOnly();
}
catch ( SystemException se ) {
// best effort
log.error( "could not set transaction to rollback only", se );
}
} }
public void afterCompletion(int status) { public void afterCompletion(int status) {
log.trace( "transaction after completion callback [status={}]", status ); log.trace( "transaction after completion callback [status={}]", status );
try { try {
afterCompletionAction.doAction( ctx, status ); afterCompletionAction.doAction( transactionCoordinator, status );
transactionCoordinator.afterTransaction( null, status );
final boolean wasSuccessful = ( status == Status.STATUS_COMMITTED );
jdbcContext.afterTransactionCompletion( wasSuccessful, hibernateTransaction );
} }
finally { finally {
reset(); reset();
jdbcContext.cleanUpJtaSynchronizationCallbackCoordinator(); if ( transactionContext().shouldAutoClose() && ! transactionContext().isClosed() ) {
if ( ctx.shouldAutoClose() && !ctx.isClosed() ) {
log.trace( "automatically closing session" ); log.trace( "automatically closing session" );
ctx.managedClose(); transactionContext().managedClose();
} }
} }
} }
private static final BeforeCompletionManagedFlushChecker STANDARD_MANAGED_FLUSH_CHECKER = new BeforeCompletionManagedFlushChecker() { private TransactionContext transactionContext() {
public boolean shouldDoManagedFlush(TransactionFactory.Context ctx, Transaction jtaTransaction) return transactionCoordinator.getTransactionContext();
throws SystemException { }
return !ctx.isClosed() &&
!ctx.isFlushModeNever() && private static final ManagedFlushChecker STANDARD_MANAGED_FLUSH_CHECKER = new ManagedFlushChecker() {
ctx.isFlushBeforeCompletionEnabled() && @Override
!JTAHelper.isRollback( jtaTransaction.getStatus() ); public boolean shouldDoManagedFlush(TransactionCoordinator coordinator, int jtaStatus) {
//actually, this last test is probably unnecessary, since return coordinator.getTransactionContext().isFlushModeNever() &&
//beforeCompletion() doesn't get called during rollback coordinator.getTransactionContext().isFlushBeforeCompletionEnabled() &&
!JtaStatusHelper.isRollback( jtaStatus );
} }
}; };
@ -178,7 +158,8 @@ public class CallbackCoordinator {
}; };
private static final AfterCompletionAction STANDARD_AFTER_COMPLETION_ACTION = new AfterCompletionAction() { private static final AfterCompletionAction STANDARD_AFTER_COMPLETION_ACTION = new AfterCompletionAction() {
public void doAction(TransactionFactory.Context ctx, int status) { @Override
public void doAction(TransactionCoordinator transactionCoordinator, int status) {
// nothing to do by default. // nothing to do by default.
} }
}; };

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.synchronization.spi;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
/**
* A pluggable strategy for defining any actions to be performed during
* {@link javax.transaction.Synchronization#afterCompletion} processing from the the
* {@link javax.transaction.Synchronization} registered by Hibernate with the underlying JTA platform.
*
* @author Steve Ebersole
*/
public interface AfterCompletionAction {
public void doAction(TransactionCoordinator transactionCoordinator, int status);
}

View File

@ -1,7 +1,7 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc. * distributed under license by Red Hat Inc.
@ -21,18 +21,20 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.transaction.synchronization; package org.hibernate.engine.transaction.synchronization.spi;
import javax.transaction.SystemException; import javax.transaction.SystemException;
import java.io.Serializable;
/** /**
* TODO : javadoc * A pluggable strategy for defining how the {@link javax.transaction.Synchronization} registered by Hibernate handles
* exceptions.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface ExceptionMapper { public interface ExceptionMapper extends Serializable {
/** /**
* Map a JTA {@link SystemException} to the appropriate runtime-based exception. * Map a JTA {@link javax.transaction.SystemException} to the appropriate runtime-based exception.
* *
* @param message The message to use for the returned exception * @param message The message to use for the returned exception
* @param systemException The causal exception * @param systemException The causal exception

View File

@ -1,7 +1,7 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc. * distributed under license by Red Hat Inc.
@ -21,31 +21,27 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.transaction.synchronization; package org.hibernate.engine.transaction.synchronization.spi;
import javax.transaction.SystemException; import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import javax.transaction.Transaction;
import org.hibernate.transaction.TransactionFactory; import java.io.Serializable;
/** /**
* Contract for checking whether to perform a managed flush in a * A pluggable strategy for defining how the {@link javax.transaction.Synchronization} registered by Hibernate determines
* {@link javax.transaction.Synchronization#beforeCompletion()} callback * whether to perform a managed flush. An exceptions from either this delegate or the subsequent flush are routed
* through the sister strategy {@link ExceptionMapper}.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface BeforeCompletionManagedFlushChecker { public interface ManagedFlushChecker extends Serializable {
/** /**
* Check whether we should perform the managed flush * Check whether we should perform the managed flush
* *
* @param ctx The Hibernate "transaction context" * @param coordinator The transaction coordinator
* @param jtaTransaction The JTA transaction * @param jtaStatus The status of the current JTA transaction.
* *
* @return True to indicate to perform the managed flush; false otherwise. * @return True to indicate to perform the managed flush; false otherwise.
*
* @throws SystemException Can be thrown while accessing the JTA transaction; will result in transaction being
* marked for rollback (best effort).
*/ */
public boolean shouldDoManagedFlush(TransactionFactory.Context ctx, Transaction jtaTransaction) public boolean shouldDoManagedFlush(TransactionCoordinator coordinator, int jtaStatus);
throws SystemException;
} }

View File

@ -0,0 +1,35 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.transaction.synchronization.spi;
import javax.transaction.Synchronization;
/**
* @author Steve Ebersole
*/
public interface SynchronizationCallbackCoordinator extends Synchronization{
public void setManagedFlushChecker(ManagedFlushChecker managedFlushChecker);
public void setAfterCompletionAction(AfterCompletionAction afterCompletionAction);
public void setExceptionMapper(ExceptionMapper exceptionMapper);
}

View File

@ -313,7 +313,7 @@ public abstract class AbstractFlushingEventListener implements Serializable {
log.trace("executing flush"); log.trace("executing flush");
try { try {
session.getJDBCContext().getConnectionManager().flushBeginning(); session.getTransactionCoordinator().getJdbcCoordinator().flushBeginning();
// we need to lock the collection caches before // we need to lock the collection caches before
// executing entity inserts/updates in order to // executing entity inserts/updates in order to
// account for bidi associations // account for bidi associations
@ -325,7 +325,7 @@ public abstract class AbstractFlushingEventListener implements Serializable {
throw he; throw he;
} }
finally { finally {
session.getJDBCContext().getConnectionManager().flushEnding(); session.getTransactionCoordinator().getJdbcCoordinator().flushEnding();
} }
} }

View File

@ -259,7 +259,7 @@ public abstract class AbstractSaveEventListener extends AbstractReassociateEvent
Serializable id = key == null ? null : key.getIdentifier(); Serializable id = key == null ? null : key.getIdentifier();
boolean inTxn = source.getJDBCContext().isTransactionInProgress(); boolean inTxn = source.getTransactionCoordinator().isTransactionInProgress();
boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess; boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
// Put a placeholder in entries, so we don't recurse back and try to save() the // Put a placeholder in entries, so we don't recurse back and try to save() the

View File

@ -26,6 +26,7 @@ package org.hibernate.exception;
import org.hibernate.JDBCException; import org.hibernate.JDBCException;
import java.io.Serializable;
import java.sql.SQLException; import java.sql.SQLException;
/** /**
@ -42,9 +43,9 @@ import java.sql.SQLException;
* @author Steve Ebersole * @author Steve Ebersole
* @see SQLExceptionConverterFactory * @see SQLExceptionConverterFactory
*/ */
public interface SQLExceptionConverter { public interface SQLExceptionConverter extends Serializable {
/** /**
* Convert the given SQLException into Hibernate's JDBCException hierarchy. * Convert the given SQLException into the Hibernate {@link JDBCException} hierarchy.
* *
* @param sqlException The SQLException to be converted. * @param sqlException The SQLException to be converted.
* @param message An optional error message. * @param message An optional error message.

View File

@ -23,35 +23,33 @@
*/ */
package org.hibernate.hql.ast.exec; package org.hibernate.hql.ast.exec;
import java.sql.PreparedStatement; import antlr.RecognitionException;
import java.sql.Connection; import antlr.collections.AST;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.List;
import java.util.Collections;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.action.BulkOperationCleanupAction; import org.hibernate.action.BulkOperationCleanupAction;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.transaction.Isolater;
import org.hibernate.engine.transaction.IsolatedWork;
import org.hibernate.event.EventSource; import org.hibernate.event.EventSource;
import org.hibernate.hql.ast.HqlSqlWalker; import org.hibernate.hql.ast.HqlSqlWalker;
import org.hibernate.hql.ast.SqlGenerator; import org.hibernate.hql.ast.SqlGenerator;
import org.hibernate.jdbc.Work;
import org.hibernate.persister.entity.Queryable; import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.InsertSelect; import org.hibernate.sql.InsertSelect;
import org.hibernate.sql.Select; import org.hibernate.sql.Select;
import org.hibernate.sql.SelectFragment; import org.hibernate.sql.SelectFragment;
import org.hibernate.util.JDBCExceptionReporter; import org.hibernate.util.JDBCExceptionReporter;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
import antlr.RecognitionException;
import antlr.collections.AST;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.Collections;
import java.util.List;
/** /**
* Implementation of AbstractStatementExecutor. * Implementation of AbstractStatementExecutor.
* *
@ -139,42 +137,55 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
" from " + persister.getTemporaryIdTableName(); " from " + persister.getTemporaryIdTableName();
} }
private static class TemporaryTableCreationWork implements Work {
private final Queryable persister;
private TemporaryTableCreationWork(Queryable persister) {
this.persister = persister;
}
@Override
public void execute(Connection connection) {
try {
Statement statement = connection.createStatement();
try {
statement.executeUpdate( persister.getTemporaryIdTableDDL() );
JDBCExceptionReporter.handleAndClearWarnings( statement, CREATION_WARNING_HANDLER );
}
finally {
try {
statement.close();
}
catch( Throwable ignore ) {
// ignore
}
}
}
catch( Exception e ) {
LOG.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
}
}
}
protected void createTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) { protected void createTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
// Don't really know all the codes required to adequately decipher returned jdbc exceptions here. // Don't really know all the codes required to adequately decipher returned jdbc exceptions here.
// simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail // simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
IsolatedWork work = new IsolatedWork() { TemporaryTableCreationWork work = new TemporaryTableCreationWork( persister );
public void doWork(Connection connection) throws HibernateException {
try {
Statement statement = connection.createStatement();
try {
statement.executeUpdate( persister.getTemporaryIdTableDDL() );
JDBCExceptionReporter.handleAndClearWarnings( statement, CREATION_WARNING_HANDLER );
}
finally {
try {
statement.close();
}
catch( Throwable ignore ) {
// ignore
}
}
}
catch( Exception e ) {
log.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
}
}
};
if ( shouldIsolateTemporaryTableDDL() ) { if ( shouldIsolateTemporaryTableDDL() ) {
if ( getFactory().getSettings().isDataDefinitionInTransactionSupported() ) { session.getTransactionCoordinator()
Isolater.doIsolatedWork( work, session ); .getTransaction()
} .createIsolationDelegate()
else { .delegateWork( work, getFactory().getSettings().isDataDefinitionInTransactionSupported() );
Isolater.doNonTransactedWork( work, session );
}
} }
else { else {
work.doWork( session.getJDBCContext().getConnectionManager().getConnection() ); final Connection connection = session.getTransactionCoordinator()
session.getJDBCContext().getConnectionManager().afterStatement(); .getJdbcCoordinator()
.getLogicalConnection()
.getShareableConnectionProxy();
work.execute( connection );
session.getTransactionCoordinator()
.getJdbcCoordinator()
.getLogicalConnection()
.afterStatementExecution();
} }
} }
@ -194,53 +205,67 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
} }
}; };
protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) { private static class TemporaryTableDropWork implements Work {
if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) { private final Queryable persister;
IsolatedWork work = new IsolatedWork() { private final SessionImplementor session;
public void doWork(Connection connection) throws HibernateException {
final String command = session.getFactory().getDialect().getDropTemporaryTableString()
+ ' ' + persister.getTemporaryIdTableName();
try {
Statement statement = connection.createStatement();
try {
statement = connection.createStatement();
statement.executeUpdate( command );
}
finally {
try {
statement.close();
}
catch( Throwable ignore ) {
// ignore
}
}
}
catch( Exception e ) {
log.warn( "unable to drop temporary id table after use [" + e.getMessage() + "]" );
}
}
};
if ( shouldIsolateTemporaryTableDDL() ) { private TemporaryTableDropWork(Queryable persister, SessionImplementor session) {
if ( getFactory().getSettings().isDataDefinitionInTransactionSupported() ) { this.persister = persister;
Isolater.doIsolatedWork( work, session ); this.session = session;
}
@Override
public void execute(Connection connection) {
final String command = session.getFactory().getDialect().getDropTemporaryTableString()
+ ' ' + persister.getTemporaryIdTableName();
try {
Statement statement = connection.createStatement();
try {
statement = connection.createStatement();
statement.executeUpdate( command );
} }
else { finally {
Isolater.doNonTransactedWork( work, session ); try {
statement.close();
}
catch( Throwable ignore ) {
// ignore
}
} }
} }
catch( Exception e ) {
LOG.warn( "unable to drop temporary id table after use [" + e.getMessage() + "]" );
}
}
}
protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) {
TemporaryTableDropWork work = new TemporaryTableDropWork( persister, session );
if ( shouldIsolateTemporaryTableDDL() ) {
session.getTransactionCoordinator()
.getTransaction()
.createIsolationDelegate()
.delegateWork( work, getFactory().getSettings().isDataDefinitionInTransactionSupported() );
}
else { else {
work.doWork( session.getJDBCContext().getConnectionManager().getConnection() ); final Connection connection = session.getTransactionCoordinator()
session.getJDBCContext().getConnectionManager().afterStatement(); .getJdbcCoordinator()
.getLogicalConnection()
.getShareableConnectionProxy();
work.execute( connection );
session.getTransactionCoordinator()
.getJdbcCoordinator()
.getLogicalConnection()
.afterStatementExecution();
} }
} }
else { else {
// at the very least cleanup the data :) // at the very least cleanup the data :)
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
ps = session.getJDBCContext().getConnectionManager().prepareStatement( "delete from " + persister.getTemporaryIdTableName(), final String sql = "delete from " + persister.getTemporaryIdTableName();
false ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
);
ps.executeUpdate(); ps.executeUpdate();
} }
catch( Throwable t ) { catch( Throwable t ) {

View File

@ -84,7 +84,7 @@ public class BasicExecutor extends AbstractStatementExecutor {
try { try {
try { try {
st = session.getJDBCContext().getConnectionManager().prepareStatement( sql, false ); st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
Iterator parameterSpecifications = this.parameterSpecifications.iterator(); Iterator parameterSpecifications = this.parameterSpecifications.iterator();
int pos = 1; int pos = 1;
while ( parameterSpecifications.hasNext() ) { while ( parameterSpecifications.hasNext() ) {

View File

@ -105,7 +105,7 @@ public class MultiTableDeleteExecutor extends AbstractStatementExecutor {
int resultCount = 0; int resultCount = 0;
try { try {
try { try {
ps = session.getJDBCContext().getConnectionManager().prepareStatement( idInsertSelect, false ); ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( idInsertSelect, false );
Iterator paramSpecifications = getIdSelectParameterSpecifications().iterator(); Iterator paramSpecifications = getIdSelectParameterSpecifications().iterator();
int pos = 1; int pos = 1;
while ( paramSpecifications.hasNext() ) { while ( paramSpecifications.hasNext() ) {
@ -132,7 +132,7 @@ public class MultiTableDeleteExecutor extends AbstractStatementExecutor {
for ( int i = 0; i < deletes.length; i++ ) { for ( int i = 0; i < deletes.length; i++ ) {
try { try {
try { try {
ps = session.getJDBCContext().getConnectionManager().prepareStatement( deletes[i], false ); ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( deletes[i], false );
ps.executeUpdate(); ps.executeUpdate();
} }
finally { finally {

View File

@ -129,7 +129,7 @@ public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
int resultCount = 0; int resultCount = 0;
try { try {
try { try {
ps = session.getJDBCContext().getConnectionManager().prepareStatement( idInsertSelect, false ); ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( idInsertSelect, false );
// int parameterStart = getWalker().getNumberOfParametersInSetClause(); // int parameterStart = getWalker().getNumberOfParametersInSetClause();
// List allParams = getIdSelectParameterSpecifications(); // List allParams = getIdSelectParameterSpecifications();
// Iterator whereParams = allParams.subList( parameterStart, allParams.size() ).iterator(); // Iterator whereParams = allParams.subList( parameterStart, allParams.size() ).iterator();
@ -161,7 +161,7 @@ public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
} }
try { try {
try { try {
ps = session.getJDBCContext().getConnectionManager().prepareStatement( updates[i], false ); ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( updates[i], false );
if ( hqlParameters[i] != null ) { if ( hqlParameters[i] != null ) {
int position = 1; // jdbc params are 1-based int position = 1; // jdbc params are 1-based
for ( int x = 0; x < hqlParameters[i].length; x++ ) { for ( int x = 0; x < hqlParameters[i].length; x++ ) {

View File

@ -58,7 +58,7 @@ public class GUIDGenerator implements IdentifierGenerator {
final String sql = session.getFactory().getDialect().getSelectGUIDString(); final String sql = session.getFactory().getDialect().getSelectGUIDString();
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement(sql); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
ResultSet rs = st.executeQuery(); ResultSet rs = st.executeQuery();
final String result; final String result;

View File

@ -87,7 +87,10 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
} }
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException { protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
return session.getJDBCContext().getConnectionManager().prepareStatement( insertSQL, PreparedStatement.RETURN_GENERATED_KEYS ); return session.getTransactionCoordinator()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( insertSQL, PreparedStatement.RETURN_GENERATED_KEYS );
} }
public Serializable executeAndExtract(PreparedStatement insert) throws SQLException { public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
@ -131,7 +134,10 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
} }
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException { protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
return session.getJDBCContext().getConnectionManager().prepareStatement( insertSQL, PreparedStatement.NO_GENERATED_KEYS ); return session.getTransactionCoordinator()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( insertSQL, PreparedStatement.NO_GENERATED_KEYS );
} }
public Serializable executeAndExtract(PreparedStatement insert) throws SQLException { public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {

View File

@ -121,7 +121,7 @@ public class IncrementGenerator implements IdentifierGenerator, Configurable {
log.debug( "fetching initial value: " + sql ); log.debug( "fetching initial value: " + sql );
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
ResultSet rs = st.executeQuery(); ResultSet rs = st.executeQuery();
try { try {

View File

@ -106,7 +106,7 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu
protected IntegralDataTypeHolder generateHolder(SessionImplementor session) { protected IntegralDataTypeHolder generateHolder(SessionImplementor session) {
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
ResultSet rs = st.executeQuery(); ResultSet rs = st.executeQuery();
try { try {

View File

@ -96,7 +96,7 @@ public class SequenceIdentityGenerator extends SequenceGenerator
} }
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException { protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
return session.getJDBCContext().getConnectionManager().prepareStatement( insertSQL, keyColumns ); return session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( insertSQL, keyColumns );
} }
protected Serializable executeAndExtract(PreparedStatement insert) throws SQLException { protected Serializable executeAndExtract(PreparedStatement insert) throws SQLException {

View File

@ -102,7 +102,7 @@ public class SequenceStructure implements DatabaseStructure {
public IntegralDataTypeHolder getNextValue() { public IntegralDataTypeHolder getNextValue() {
accessCounter++; accessCounter++;
try { try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
ResultSet rs = st.executeQuery(); ResultSet rs = st.executeQuery();
try { try {

View File

@ -50,7 +50,10 @@ public abstract class AbstractSelectingDelegate implements InsertGeneratedIdenti
public final Serializable performInsert(String insertSQL, SessionImplementor session, Binder binder) { public final Serializable performInsert(String insertSQL, SessionImplementor session, Binder binder) {
try { try {
// prepare and execute the insert // prepare and execute the insert
PreparedStatement insert = session.getJDBCContext().getConnectionManager().prepareStatement( insertSQL, PreparedStatement.NO_GENERATED_KEYS ); PreparedStatement insert = session.getTransactionCoordinator()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( insertSQL, PreparedStatement.NO_GENERATED_KEYS );
try { try {
binder.bindValues( insert ); binder.bindValues( insert );
insert.executeUpdate(); insert.executeUpdate();
@ -71,7 +74,10 @@ public abstract class AbstractSelectingDelegate implements InsertGeneratedIdenti
try { try {
//fetch the generated id in a separate query //fetch the generated id in a separate query
PreparedStatement idSelect = session.getJDBCContext().getConnectionManager().prepareStatement( selectSQL, false ); PreparedStatement idSelect = session.getTransactionCoordinator()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( selectSQL, false );
try { try {
bindParameters( session, idSelect, binder.getEntity() ); bindParameters( session, idSelect, binder.getEntity() );
ResultSet rs = idSelect.executeQuery(); ResultSet rs = idSelect.executeQuery();

View File

@ -38,6 +38,8 @@ import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.query.HQLQueryPlan; import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan; import org.hibernate.engine.query.NativeSQLQueryPlan;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
import java.util.List; import java.util.List;
@ -46,7 +48,7 @@ import java.util.List;
* *
* @author Gavin King * @author Gavin King
*/ */
public abstract class AbstractSessionImpl implements SessionImplementor { public abstract class AbstractSessionImpl implements SessionImplementor, TransactionContext {
protected transient SessionFactoryImpl factory; protected transient SessionFactoryImpl factory;
private boolean closed = false; private boolean closed = false;
@ -59,6 +61,11 @@ public abstract class AbstractSessionImpl implements SessionImplementor {
return factory; return factory;
} }
@Override
public TransactionEnvironment getTransactionEnvironment() {
return factory.getTransactionEnvironment();
}
public boolean isClosed() { public boolean isClosed() {
return closed; return closed;
} }

View File

@ -0,0 +1,59 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.impl;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
import java.io.Serializable;
import java.sql.Connection;
/**
* @author Steve Ebersole
*/
public class ConnectionObserverStatsBridge implements ConnectionObserver, Serializable {
private final SessionFactoryImplementor sessionFactory;
public ConnectionObserverStatsBridge(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public void physicalConnectionObtained(Connection connection) {
sessionFactory.getStatisticsImplementor().connect();
}
@Override
public void physicalConnectionReleased() {
}
@Override
public void logicalConnectionClosed() {
}
@Override
public void statementPrepared() {
sessionFactory.getStatisticsImplementor().prepareStatement();
}
}

View File

@ -23,32 +23,6 @@
*/ */
package org.hibernate.impl; package org.hibernate.impl;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.transaction.TransactionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.Cache; import org.hibernate.Cache;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
@ -76,10 +50,6 @@ import org.hibernate.cache.impl.CacheDataDescriptionImpl;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Settings; import org.hibernate.cfg.Settings;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.context.CurrentSessionContext; import org.hibernate.context.CurrentSessionContext;
import org.hibernate.context.JTASessionContext; import org.hibernate.context.JTASessionContext;
import org.hibernate.context.ManagedSessionContext; import org.hibernate.context.ManagedSessionContext;
@ -92,12 +62,16 @@ import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.engine.NamedSQLQueryDefinition; import org.hibernate.engine.NamedSQLQueryDefinition;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.profile.Association; import org.hibernate.engine.profile.Association;
import org.hibernate.engine.profile.Fetch; import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.FetchProfile; import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.query.QueryPlanCache; import org.hibernate.engine.query.QueryPlanCache;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification; import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
import org.hibernate.event.EventListeners; import org.hibernate.event.EventListeners;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDGenerator; import org.hibernate.id.UUIDGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.id.factory.IdentifierGeneratorFactory;
@ -113,6 +87,8 @@ import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Queryable; import org.hibernate.persister.entity.Queryable;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.service.spi.ServiceRegistry; import org.hibernate.service.spi.ServiceRegistry;
import org.hibernate.stat.ConcurrentStatisticsImpl; import org.hibernate.stat.ConcurrentStatisticsImpl;
import org.hibernate.stat.Statistics; import org.hibernate.stat.Statistics;
@ -120,7 +96,6 @@ import org.hibernate.stat.StatisticsImplementor;
import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.hibernate.tool.hbm2ddl.SchemaValidator; import org.hibernate.tool.hbm2ddl.SchemaValidator;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.tuple.entity.EntityTuplizer; import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -128,6 +103,31 @@ import org.hibernate.type.TypeResolver;
import org.hibernate.util.CollectionHelper; import org.hibernate.util.CollectionHelper;
import org.hibernate.util.EmptyIterator; import org.hibernate.util.EmptyIterator;
import org.hibernate.util.ReflectHelper; import org.hibernate.util.ReflectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.transaction.TransactionManager;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/** /**
@ -153,7 +153,8 @@ import org.hibernate.util.ReflectHelper;
* @see org.hibernate.persister.collection.CollectionPersister * @see org.hibernate.persister.collection.CollectionPersister
* @author Gavin King * @author Gavin King
*/ */
public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor { public final class SessionFactoryImpl
implements SessionFactory, SessionFactoryImplementor {
private static final Logger log = LoggerFactory.getLogger(SessionFactoryImpl.class); private static final Logger log = LoggerFactory.getLogger(SessionFactoryImpl.class);
private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator(); private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator();
@ -178,7 +179,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
private final transient Settings settings; private final transient Settings settings;
private final transient Properties properties; private final transient Properties properties;
private transient SchemaExport schemaExport; private transient SchemaExport schemaExport;
private final transient TransactionManager transactionManager;
private final transient QueryCache queryCache; private final transient QueryCache queryCache;
private final transient UpdateTimestampsCache updateTimestampsCache; private final transient UpdateTimestampsCache updateTimestampsCache;
private final transient Map<String,QueryCache> queryCaches; private final transient Map<String,QueryCache> queryCaches;
@ -195,6 +195,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
private transient boolean isClosed = false; private transient boolean isClosed = false;
private final transient TypeResolver typeResolver; private final transient TypeResolver typeResolver;
private final transient TypeHelper typeHelper; private final transient TypeHelper typeHelper;
private final transient TransactionEnvironment transactionEnvironment;
public SessionFactoryImpl( public SessionFactoryImpl(
Configuration cfg, Configuration cfg,
@ -386,17 +387,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
schemaExport = new SchemaExport( getJdbcServices(), cfg ); schemaExport = new SchemaExport( getJdbcServices(), cfg );
} }
if ( settings.getTransactionManagerLookup()!=null ) {
log.debug("obtaining JTA TransactionManager");
transactionManager = settings.getTransactionManagerLookup().getTransactionManager(properties);
}
else {
if ( settings.getTransactionFactory().isTransactionManagerRequired() ) {
throw new HibernateException("The chosen transaction strategy requires access to the JTA TransactionManager");
}
transactionManager = null;
}
currentSessionContext = buildCurrentSessionContext(); currentSessionContext = buildCurrentSessionContext();
if ( settings.isQueryCacheEnabled() ) { if ( settings.isQueryCacheEnabled() ) {
@ -480,9 +470,14 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
fetchProfiles.put( fetchProfile.getName(), fetchProfile ); fetchProfiles.put( fetchProfile.getName(), fetchProfile );
} }
this.transactionEnvironment = new TransactionEnvironmentImpl( this );
this.observer.sessionFactoryCreated( this ); this.observer.sessionFactoryCreated( this );
} }
public TransactionEnvironment getTransactionEnvironment() {
return transactionEnvironment;
}
public Properties getProperties() { public Properties getProperties() {
return properties; return properties;
} }
@ -728,14 +723,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
return interceptor; return interceptor;
} }
public TransactionFactory getTransactionFactory() {
return settings.getTransactionFactory();
}
public TransactionManager getTransactionManager() {
return transactionManager;
}
public SQLExceptionConverter getSQLExceptionConverter() { public SQLExceptionConverter getSQLExceptionConverter() {
return getSQLExceptionHelper().getSqlExceptionConverter(); return getSQLExceptionHelper().getSqlExceptionConverter();
} }
@ -1229,19 +1216,34 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
return (IdentifierGenerator) identifierGenerators.get(rootEntityName); return (IdentifierGenerator) identifierGenerators.get(rootEntityName);
} }
private org.hibernate.engine.transaction.spi.TransactionFactory transactionFactory() {
return serviceRegistry.getService( org.hibernate.engine.transaction.spi.TransactionFactory.class );
}
private boolean canAccessTransactionManager() {
try {
return serviceRegistry.getService( JtaPlatform.class ).retrieveTransactionManager() != null;
}
catch (Exception e) {
return false;
}
}
private CurrentSessionContext buildCurrentSessionContext() { private CurrentSessionContext buildCurrentSessionContext() {
String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS ); String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
// for backward-compatability // for backward-compatibility
if ( impl == null && transactionManager != null ) { if ( impl == null ) {
impl = "jta"; if ( canAccessTransactionManager() ) {
impl = "jta";
}
else {
return null;
}
} }
if ( impl == null ) { if ( "jta".equals( impl ) ) {
return null; if ( ! transactionFactory().compatibleWithJtaSynchronization() ) {
} log.warn( "JTASessionContext being used with JdbcTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
else if ( "jta".equals( impl ) ) {
if ( settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions() ) {
log.warn( "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
} }
return new JTASessionContext( this ); return new JTASessionContext( this );
} }
@ -1256,7 +1258,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
Class implClass = ReflectHelper.classForName( impl ); Class implClass = ReflectHelper.classForName( impl );
return ( CurrentSessionContext ) implClass return ( CurrentSessionContext ) implClass
.getConstructor( new Class[] { SessionFactoryImplementor.class } ) .getConstructor( new Class[] { SessionFactoryImplementor.class } )
.newInstance( new Object[] { this } ); .newInstance( this );
} }
catch( Throwable t ) { catch( Throwable t ) {
log.error( "Unable to construct current session context [" + impl + "]", t ); log.error( "Unable to construct current session context [" + impl + "]", t );
@ -1265,11 +1267,15 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
} }
} }
public EventListeners getEventListeners() public EventListeners getEventListeners() {
{
return eventListeners; return eventListeners;
} }
@Override
public ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
public EntityNotFoundDelegate getEntityNotFoundDelegate() { public EntityNotFoundDelegate getEntityNotFoundDelegate() {
return entityNotFoundDelegate; return entityNotFoundDelegate;
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2005-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,44 +20,21 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.impl; package org.hibernate.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.Criteria; import org.hibernate.Criteria;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.Filter; import org.hibernate.Filter;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Interceptor; import org.hibernate.Interceptor;
import org.hibernate.LobHelper; import org.hibernate.LobHelper;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.ObjectDeletedException; import org.hibernate.ObjectDeletedException;
import org.hibernate.Query; import org.hibernate.Query;
@ -68,33 +45,34 @@ import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionException; import org.hibernate.SessionException;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.TransientObjectException; import org.hibernate.TransientObjectException;
import org.hibernate.TypeHelper; import org.hibernate.TypeHelper;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.UnknownProfileException; import org.hibernate.UnknownProfileException;
import org.hibernate.EntityNameResolver; import org.hibernate.UnresolvableObjectException;
import org.hibernate.LockOptions;
import org.hibernate.collection.PersistentCollection; import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.ActionQueue; import org.hibernate.engine.ActionQueue;
import org.hibernate.engine.CollectionEntry; import org.hibernate.engine.CollectionEntry;
import org.hibernate.engine.EntityEntry; import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.EntityKey; import org.hibernate.engine.EntityKey;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.NonFlushedChanges; import org.hibernate.engine.NonFlushedChanges;
import org.hibernate.engine.PersistenceContext; import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.StatefulPersistenceContext; import org.hibernate.engine.StatefulPersistenceContext;
import org.hibernate.engine.Status; import org.hibernate.engine.Status;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.jdbc.LobCreationContext; import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator; import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.internal.JDBCContextImpl;
import org.hibernate.engine.jdbc.spi.JDBCContext;
import org.hibernate.engine.query.FilterQueryPlan; import org.hibernate.engine.query.FilterQueryPlan;
import org.hibernate.engine.query.HQLQueryPlan; import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan; import org.hibernate.engine.query.NativeSQLQueryPlan;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification; import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.engine.transaction.spi.TransactionObserver;
import org.hibernate.event.AutoFlushEvent; import org.hibernate.event.AutoFlushEvent;
import org.hibernate.event.AutoFlushEventListener; import org.hibernate.event.AutoFlushEventListener;
import org.hibernate.event.DeleteEvent; import org.hibernate.event.DeleteEvent;
@ -136,57 +114,84 @@ import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.LazyInitializer;
import org.hibernate.stat.SessionStatistics; import org.hibernate.stat.SessionStatistics;
import org.hibernate.stat.SessionStatisticsImpl; import org.hibernate.stat.SessionStatisticsImpl;
import org.hibernate.type.Type;
import org.hibernate.type.SerializationException; import org.hibernate.type.SerializationException;
import org.hibernate.type.Type;
import org.hibernate.util.ArrayHelper; import org.hibernate.util.ArrayHelper;
import org.hibernate.util.CollectionHelper; import org.hibernate.util.CollectionHelper;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* Concrete implementation of a Session, and also the central, organizing component * Concrete implementation of a Session.
* of Hibernate's internal implementation. As such, this class exposes two interfaces; *
* Session itself, to the application, and SessionImplementor, to other components * Exposes two interfaces:<ul>
* of Hibernate. This class is not threadsafe. * <li>{@link Session} to the application</li>
* <li>{@link org.hibernate.engine.SessionImplementor} to other Hibernate components (SPI)</li>
* </ul>
*
* This class is not thread-safe.
* *
* @author Gavin King * @author Gavin King
*/ */
public final class SessionImpl extends AbstractSessionImpl public final class SessionImpl
implements EventSource, org.hibernate.classic.Session, JDBCContext.Context, LobCreationContext { extends AbstractSessionImpl
implements EventSource,
org.hibernate.classic.Session,
TransactionContext,
LobCreationContext {
// todo : need to find a clean way to handle the "event source" role // todo : need to find a clean way to handle the "event source" role
// a seperate classs responsible for generating/dispatching events just duplicates most of the Session methods... // a separate class responsible for generating/dispatching events just duplicates most of the Session methods...
// passing around seperate reto interceptor, factory, actionQueue, and persistentContext is not manageable... // passing around separate interceptor, factory, actionQueue, and persistentContext is not manageable...
private static final Logger log = LoggerFactory.getLogger(SessionImpl.class); private static final Logger log = LoggerFactory.getLogger(SessionImpl.class);
private transient EntityMode entityMode = EntityMode.POJO;
private transient boolean autoClear; //for EJB3
private transient long timestamp; private transient long timestamp;
private transient FlushMode flushMode = FlushMode.AUTO;
private transient CacheMode cacheMode = CacheMode.NORMAL;
private transient Interceptor interceptor;
private transient int dontFlushFromFind = 0;
private transient ActionQueue actionQueue; private transient ActionQueue actionQueue;
private transient StatefulPersistenceContext persistenceContext; private transient StatefulPersistenceContext persistenceContext;
private transient JDBCContextImpl jdbcContext; private transient TransactionCoordinatorImpl transactionCoordinator;
private transient EventListeners listeners; private transient EventListeners listeners;
private transient Interceptor interceptor;
private transient EntityNameResolver entityNameResolver = new CoordinatingEntityNameResolver();
private transient ConnectionReleaseMode connectionReleaseMode;
private transient FlushMode flushMode = FlushMode.AUTO;
private transient CacheMode cacheMode = CacheMode.NORMAL;
private transient EntityMode entityMode = EntityMode.POJO;
private transient boolean autoClear; //for EJB3
private transient int dontFlushFromFind = 0;
private transient boolean flushBeforeCompletionEnabled; private transient boolean flushBeforeCompletionEnabled;
private transient boolean autoCloseSessionEnabled; private transient boolean autoCloseSessionEnabled;
private transient ConnectionReleaseMode connectionReleaseMode;
private transient LoadQueryInfluencers loadQueryInfluencers; private transient LoadQueryInfluencers loadQueryInfluencers;
private transient Session rootSession; private transient Session rootSession;
private transient Map childSessionsByEntityMode; private transient Map childSessionsByEntityMode;
private transient EntityNameResolver entityNameResolver = new CoordinatingEntityNameResolver();
/** /**
* Constructor used in building "child sessions". * Constructor used in building "child sessions".
* *
@ -197,7 +202,7 @@ public final class SessionImpl extends AbstractSessionImpl
super( parent.factory ); super( parent.factory );
this.rootSession = parent; this.rootSession = parent;
this.timestamp = parent.timestamp; this.timestamp = parent.timestamp;
this.jdbcContext = parent.jdbcContext; this.transactionCoordinator = parent.transactionCoordinator;
this.interceptor = parent.interceptor; this.interceptor = parent.interceptor;
this.listeners = parent.listeners; this.listeners = parent.listeners;
this.actionQueue = new ActionQueue( this ); this.actionQueue = new ActionQueue( this );
@ -251,7 +256,11 @@ public final class SessionImpl extends AbstractSessionImpl
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled; this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
this.autoCloseSessionEnabled = autoCloseSessionEnabled; this.autoCloseSessionEnabled = autoCloseSessionEnabled;
this.connectionReleaseMode = connectionReleaseMode; this.connectionReleaseMode = connectionReleaseMode;
this.jdbcContext = new JDBCContextImpl( this, connection, interceptor );
this.transactionCoordinator = new TransactionCoordinatorImpl( connection, this );
this.transactionCoordinator.getJdbcCoordinator().getLogicalConnection().addObserver(
new ConnectionObserverStatsBridge( factory )
);
loadQueryInfluencers = new LoadQueryInfluencers( factory ); loadQueryInfluencers = new LoadQueryInfluencers( factory );
@ -330,7 +339,7 @@ public final class SessionImpl extends AbstractSessionImpl
} }
if ( rootSession == null ) { if ( rootSession == null ) {
return jdbcContext.getConnectionManager().close(); return transactionCoordinator.close();
} }
else { else {
return null; return null;
@ -343,7 +352,6 @@ public final class SessionImpl extends AbstractSessionImpl
} }
public ConnectionReleaseMode getConnectionReleaseMode() { public ConnectionReleaseMode getConnectionReleaseMode() {
checkTransactionSynchStatus();
return connectionReleaseMode; return connectionReleaseMode;
} }
@ -523,76 +531,84 @@ public final class SessionImpl extends AbstractSessionImpl
public Connection connection() throws HibernateException { public Connection connection() throws HibernateException {
errorIfClosed(); errorIfClosed();
return jdbcContext.borrowConnection(); return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getDistinctConnectionProxy();
} }
public boolean isConnected() { public boolean isConnected() {
checkTransactionSynchStatus(); checkTransactionSynchStatus();
return !isClosed() && jdbcContext.getConnectionManager().isCurrentlyConnected(); return !isClosed() && transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isOpen();
} }
public boolean isTransactionInProgress() { public boolean isTransactionInProgress() {
checkTransactionSynchStatus(); checkTransactionSynchStatus();
return !isClosed() && jdbcContext.isTransactionInProgress(); return !isClosed() && transactionCoordinator.isTransactionInProgress();
} }
public Connection disconnect() throws HibernateException { public Connection disconnect() throws HibernateException {
errorIfClosed(); errorIfClosed();
log.debug( "disconnecting session" ); log.debug( "disconnecting session" );
return jdbcContext.getConnectionManager().manualDisconnect(); return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualDisconnect();
} }
public void reconnect() throws HibernateException { public void reconnect() throws HibernateException {
errorIfClosed(); errorIfClosed();
log.debug( "reconnecting session" ); log.debug( "reconnecting session" );
checkTransactionSynchStatus(); checkTransactionSynchStatus();
jdbcContext.getConnectionManager().manualReconnect(); transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualReconnect( null );
} }
public void reconnect(Connection conn) throws HibernateException { public void reconnect(Connection conn) throws HibernateException {
errorIfClosed(); errorIfClosed();
log.debug( "reconnecting session" ); log.debug( "reconnecting session" );
checkTransactionSynchStatus(); checkTransactionSynchStatus();
jdbcContext.getConnectionManager().manualReconnect( conn ); transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualReconnect( conn );
} }
public void beforeTransactionCompletion(Transaction tx) {
log.trace( "before transaction completion" );
actionQueue.beforeTransactionCompletion();
if ( rootSession == null ) {
try {
interceptor.beforeTransactionCompletion(tx);
}
catch (Throwable t) {
log.error("exception in interceptor beforeTransactionCompletion()", t);
}
}
}
public void setAutoClear(boolean enabled) { public void setAutoClear(boolean enabled) {
errorIfClosed(); errorIfClosed();
autoClear = enabled; autoClear = enabled;
} }
/** /**
* Check if there is a Hibernate or JTA transaction in progress and, * Check if there is a Hibernate or JTA transaction in progress and,
* if there is not, flush if necessary, make sure the connection has * if there is not, flush if necessary, make sure the connection has
* been committed (if it is not in autocommit mode) and run the after * been committed (if it is not in autocommit mode) and run the after
* completion processing * completion processing
*/ */
public void afterOperation(boolean success) { public void afterOperation(boolean success) {
if ( !jdbcContext.isTransactionInProgress() ) { if ( ! transactionCoordinator.isTransactionInProgress() ) {
jdbcContext.afterNontransactionalQuery( success ); transactionCoordinator.afterNonTransactionalQuery( success );
} }
} }
public void afterTransactionCompletion(boolean success, Transaction tx) { @Override
public void afterTransactionBegin(TransactionImplementor hibernateTransaction) {
errorIfClosed();
interceptor.afterTransactionBegin( hibernateTransaction );
}
@Override
public void beforeTransactionCompletion(TransactionImplementor hibernateTransaction) {
log.trace( "before transaction completion" );
actionQueue.beforeTransactionCompletion();
if ( rootSession == null ) {
try {
interceptor.beforeTransactionCompletion( hibernateTransaction );
}
catch (Throwable t) {
log.error( "exception in interceptor beforeTransactionCompletion()", t );
}
}
}
@Override
public void afterTransactionCompletion(TransactionImplementor hibernateTransaction, boolean successful) {
log.trace( "after transaction completion" ); log.trace( "after transaction completion" );
persistenceContext.afterTransactionCompletion(); persistenceContext.afterTransactionCompletion();
actionQueue.afterTransactionCompletion(success); actionQueue.afterTransactionCompletion( successful );
if ( rootSession == null && tx != null ) { if ( rootSession == null && hibernateTransaction != null ) {
try { try {
interceptor.afterTransactionCompletion(tx); interceptor.afterTransactionCompletion( hibernateTransaction );
} }
catch (Throwable t) { catch (Throwable t) {
log.error("exception in interceptor afterTransactionCompletion()", t); log.error("exception in interceptor afterTransactionCompletion()", t);
@ -660,11 +676,11 @@ public final class SessionImpl extends AbstractSessionImpl
// saveOrUpdate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // saveOrUpdate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void saveOrUpdate(Object object) throws HibernateException { public void saveOrUpdate(Object object) throws HibernateException {
saveOrUpdate(null, object); saveOrUpdate( null, object );
} }
public void saveOrUpdate(String entityName, Object obj) throws HibernateException { public void saveOrUpdate(String entityName, Object obj) throws HibernateException {
fireSaveOrUpdate( new SaveOrUpdateEvent(entityName, obj, this) ); fireSaveOrUpdate( new SaveOrUpdateEvent( entityName, obj, this ) );
} }
private void fireSaveOrUpdate(SaveOrUpdateEvent event) { private void fireSaveOrUpdate(SaveOrUpdateEvent event) {
@ -684,15 +700,15 @@ public final class SessionImpl extends AbstractSessionImpl
} }
public Serializable save(Object obj) throws HibernateException { public Serializable save(Object obj) throws HibernateException {
return save(null, obj); return save( null, obj );
} }
public Serializable save(String entityName, Object object) throws HibernateException { public Serializable save(String entityName, Object object) throws HibernateException {
return fireSave( new SaveOrUpdateEvent(entityName, object, this) ); return fireSave( new SaveOrUpdateEvent( entityName, object, this ) );
} }
public void save(String entityName, Object object, Serializable id) throws HibernateException { public void save(String entityName, Object object, Serializable id) throws HibernateException {
fireSave( new SaveOrUpdateEvent(entityName, object, id, this) ); fireSave( new SaveOrUpdateEvent( entityName, object, id, this ) );
} }
private Serializable fireSave(SaveOrUpdateEvent event) { private Serializable fireSave(SaveOrUpdateEvent event) {
@ -713,15 +729,15 @@ public final class SessionImpl extends AbstractSessionImpl
} }
public void update(Object obj, Serializable id) throws HibernateException { public void update(Object obj, Serializable id) throws HibernateException {
update(null, obj, id); update( null, obj, id );
} }
public void update(String entityName, Object object) throws HibernateException { public void update(String entityName, Object object) throws HibernateException {
fireUpdate( new SaveOrUpdateEvent(entityName, object, this) ); fireUpdate( new SaveOrUpdateEvent( entityName, object, this ) );
} }
public void update(String entityName, Object object, Serializable id) throws HibernateException { public void update(String entityName, Object object, Serializable id) throws HibernateException {
fireUpdate(new SaveOrUpdateEvent(entityName, object, id, this)); fireUpdate( new SaveOrUpdateEvent( entityName, object, id, this ) );
} }
private void fireUpdate(SaveOrUpdateEvent event) { private void fireUpdate(SaveOrUpdateEvent event) {
@ -753,7 +769,7 @@ public final class SessionImpl extends AbstractSessionImpl
} }
private void fireLock( Object object, LockOptions options) { private void fireLock( Object object, LockOptions options) {
fireLock( new LockEvent( object, options, this) ); fireLock( new LockEvent( object, options, this ) );
} }
private void fireLock(LockEvent lockEvent) { private void fireLock(LockEvent lockEvent) {
@ -769,16 +785,16 @@ public final class SessionImpl extends AbstractSessionImpl
// persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void persist(String entityName, Object object) throws HibernateException { public void persist(String entityName, Object object) throws HibernateException {
firePersist( new PersistEvent(entityName, object, this) ); firePersist( new PersistEvent( entityName, object, this ) );
} }
public void persist(Object object) throws HibernateException { public void persist(Object object) throws HibernateException {
persist(null, object); persist( null, object );
} }
public void persist(String entityName, Object object, Map copiedAlready) public void persist(String entityName, Object object, Map copiedAlready)
throws HibernateException { throws HibernateException {
firePersist( copiedAlready, new PersistEvent(entityName, object, this) ); firePersist( copiedAlready, new PersistEvent( entityName, object, this ) );
} }
private void firePersist(Map copiedAlready, PersistEvent event) { private void firePersist(Map copiedAlready, PersistEvent event) {
@ -804,16 +820,16 @@ public final class SessionImpl extends AbstractSessionImpl
public void persistOnFlush(String entityName, Object object) public void persistOnFlush(String entityName, Object object)
throws HibernateException { throws HibernateException {
firePersistOnFlush( new PersistEvent(entityName, object, this) ); firePersistOnFlush( new PersistEvent( entityName, object, this ) );
} }
public void persistOnFlush(Object object) throws HibernateException { public void persistOnFlush(Object object) throws HibernateException {
persist(null, object); persist( null, object );
} }
public void persistOnFlush(String entityName, Object object, Map copiedAlready) public void persistOnFlush(String entityName, Object object, Map copiedAlready)
throws HibernateException { throws HibernateException {
firePersistOnFlush( copiedAlready, new PersistEvent(entityName, object, this) ); firePersistOnFlush( copiedAlready, new PersistEvent( entityName, object, this ) );
} }
private void firePersistOnFlush(Map copiedAlready, PersistEvent event) { private void firePersistOnFlush(Map copiedAlready, PersistEvent event) {
@ -838,15 +854,15 @@ public final class SessionImpl extends AbstractSessionImpl
// merge() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // merge() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public Object merge(String entityName, Object object) throws HibernateException { public Object merge(String entityName, Object object) throws HibernateException {
return fireMerge( new MergeEvent(entityName, object, this) ); return fireMerge( new MergeEvent( entityName, object, this ) );
} }
public Object merge(Object object) throws HibernateException { public Object merge(Object object) throws HibernateException {
return merge(null, object); return merge( null, object );
} }
public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException { public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException {
fireMerge( copiedAlready, new MergeEvent(entityName, object, this) ); fireMerge( copiedAlready, new MergeEvent( entityName, object, this ) );
} }
private Object fireMerge(MergeEvent event) { private Object fireMerge(MergeEvent event) {
@ -873,7 +889,7 @@ public final class SessionImpl extends AbstractSessionImpl
public Object saveOrUpdateCopy(String entityName, Object object) public Object saveOrUpdateCopy(String entityName, Object object)
throws HibernateException { throws HibernateException {
return fireSaveOrUpdateCopy( new MergeEvent(entityName, object, this) ); return fireSaveOrUpdateCopy( new MergeEvent( entityName, object, this ) );
} }
public Object saveOrUpdateCopy(Object object) throws HibernateException { public Object saveOrUpdateCopy(Object object) throws HibernateException {
@ -882,7 +898,7 @@ public final class SessionImpl extends AbstractSessionImpl
public Object saveOrUpdateCopy(String entityName, Object object, Serializable id) public Object saveOrUpdateCopy(String entityName, Object object, Serializable id)
throws HibernateException { throws HibernateException {
return fireSaveOrUpdateCopy( new MergeEvent(entityName, object, id, this) ); return fireSaveOrUpdateCopy( new MergeEvent( entityName, object, id, this ) );
} }
public Object saveOrUpdateCopy(Object object, Serializable id) public Object saveOrUpdateCopy(Object object, Serializable id)
@ -1037,7 +1053,7 @@ public final class SessionImpl extends AbstractSessionImpl
} }
public Object load(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException { public Object load(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException {
return load( entityClass.getName(), id, lockOptions); return load( entityClass.getName(), id, lockOptions );
} }
public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException { public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
@ -1057,7 +1073,7 @@ public final class SessionImpl extends AbstractSessionImpl
} }
public Object get(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException { public Object get(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException {
return get( entityClass.getName(), id, lockOptions); return get( entityClass.getName(), id, lockOptions );
} }
public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException { public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
@ -1068,7 +1084,7 @@ public final class SessionImpl extends AbstractSessionImpl
public Object get(String entityName, Serializable id, LockOptions lockOptions) throws HibernateException { public Object get(String entityName, Serializable id, LockOptions lockOptions) throws HibernateException {
LoadEvent event = new LoadEvent(id, entityName, lockOptions, this); LoadEvent event = new LoadEvent(id, entityName, lockOptions, this);
fireLoad(event, LoadEventListener.GET); fireLoad( event, LoadEventListener.GET );
return event.getResult(); return event.getResult();
} }
@ -1097,7 +1113,7 @@ public final class SessionImpl extends AbstractSessionImpl
} }
public void refresh(Object object, Map refreshedAlready) throws HibernateException { public void refresh(Object object, Map refreshedAlready) throws HibernateException {
fireRefresh( refreshedAlready, new RefreshEvent(object, this) ); fireRefresh( refreshedAlready, new RefreshEvent( object, this ) );
} }
private void fireRefresh(RefreshEvent refreshEvent) { private void fireRefresh(RefreshEvent refreshEvent) {
@ -1127,7 +1143,7 @@ public final class SessionImpl extends AbstractSessionImpl
public void replicate(String entityName, Object obj, ReplicationMode replicationMode) public void replicate(String entityName, Object obj, ReplicationMode replicationMode)
throws HibernateException { throws HibernateException {
fireReplicate( new ReplicateEvent(entityName, obj, replicationMode, this) ); fireReplicate( new ReplicateEvent( entityName, obj, replicationMode, this ) );
} }
private void fireReplicate(ReplicateEvent event) { private void fireReplicate(ReplicateEvent event) {
@ -1147,7 +1163,7 @@ public final class SessionImpl extends AbstractSessionImpl
* (references held by application or other persistant instances are okay) * (references held by application or other persistant instances are okay)
*/ */
public void evict(Object object) throws HibernateException { public void evict(Object object) throws HibernateException {
fireEvict( new EvictEvent(object, this) ); fireEvict( new EvictEvent( object, this ) );
} }
private void fireEvict(EvictEvent evictEvent) { private void fireEvict(EvictEvent evictEvent) {
@ -1289,7 +1305,7 @@ public final class SessionImpl extends AbstractSessionImpl
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
queryParameters.validateParameters(); queryParameters.validateParameters();
NativeSQLQueryPlan plan = getNativeSQLQueryPlan(nativeQuerySpecification); NativeSQLQueryPlan plan = getNativeSQLQueryPlan( nativeQuerySpecification );
autoFlushIfRequired( plan.getCustomQuery().getQuerySpaces() ); autoFlushIfRequired( plan.getCustomQuery().getQuerySpaces() );
@ -1394,11 +1410,11 @@ public final class SessionImpl extends AbstractSessionImpl
public Query getNamedQuery(String queryName) throws MappingException { public Query getNamedQuery(String queryName) throws MappingException {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
return super.getNamedQuery(queryName); return super.getNamedQuery( queryName );
} }
public Object instantiate(String entityName, Serializable id) throws HibernateException { public Object instantiate(String entityName, Serializable id) throws HibernateException {
return instantiate( factory.getEntityPersister(entityName), id ); return instantiate( factory.getEntityPersister( entityName ), id );
} }
/** /**
@ -1449,7 +1465,7 @@ public final class SessionImpl extends AbstractSessionImpl
public Transaction getTransaction() throws HibernateException { public Transaction getTransaction() throws HibernateException {
errorIfClosed(); errorIfClosed();
return jdbcContext.getTransaction(); return transactionCoordinator.getTransaction();
} }
public Transaction beginTransaction() throws HibernateException { public Transaction beginTransaction() throws HibernateException {
@ -1463,11 +1479,6 @@ public final class SessionImpl extends AbstractSessionImpl
result.begin(); result.begin();
return result; return result;
} }
public void afterTransactionBegin(Transaction tx) {
errorIfClosed();
interceptor.afterTransactionBegin(tx);
}
public EntityPersister getEntityPersister(final String entityName, final Object object) { public EntityPersister getEntityPersister(final String entityName, final Object object) {
errorIfClosed(); errorIfClosed();
@ -1522,7 +1533,7 @@ public final class SessionImpl extends AbstractSessionImpl
public Serializable getContextEntityIdentifier(Object object) { public Serializable getContextEntityIdentifier(Object object) {
errorIfClosed(); errorIfClosed();
if ( object instanceof HibernateProxy ) { if ( object instanceof HibernateProxy ) {
return getProxyIdentifier(object); return getProxyIdentifier( object );
} }
else { else {
EntityEntry entry = persistenceContext.getEntry(object); EntityEntry entry = persistenceContext.getEntry(object);
@ -1757,13 +1768,13 @@ public final class SessionImpl extends AbstractSessionImpl
public Query createQuery(String queryString) { public Query createQuery(String queryString) {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
return super.createQuery(queryString); return super.createQuery( queryString );
} }
public SQLQuery createSQLQuery(String sql) { public SQLQuery createSQLQuery(String sql) {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
return super.createSQLQuery(sql); return super.createSQLQuery( sql );
} }
public Query createSQLQuery(String sql, String returnAlias, Class returnClass) { public Query createSQLQuery(String sql, String returnAlias, Class returnClass) {
@ -1839,11 +1850,11 @@ public final class SessionImpl extends AbstractSessionImpl
} }
} }
public SessionFactory getSessionFactory() { public SessionFactoryImplementor getSessionFactory() {
checkTransactionSynchStatus(); checkTransactionSynchStatus();
return factory; return factory;
} }
public void initializeCollection(PersistentCollection collection, boolean writing) public void initializeCollection(PersistentCollection collection, boolean writing)
throws HibernateException { throws HibernateException {
errorIfClosed(); errorIfClosed();
@ -1858,7 +1869,7 @@ public final class SessionImpl extends AbstractSessionImpl
if (object instanceof HibernateProxy) { if (object instanceof HibernateProxy) {
LazyInitializer initializer = ( ( HibernateProxy ) object ).getHibernateLazyInitializer(); LazyInitializer initializer = ( ( HibernateProxy ) object ).getHibernateLazyInitializer();
// it is possible for this method to be called during flush processing, // it is possible for this method to be called during flush processing,
// so make certain that we do not accidently initialize an uninitialized proxy // so make certain that we do not accidentally initialize an uninitialized proxy
if ( initializer.isUninitialized() ) { if ( initializer.isUninitialized() ) {
return initializer.getEntityName(); return initializer.getEntityName();
} }
@ -1904,7 +1915,7 @@ public final class SessionImpl extends AbstractSessionImpl
public void cancelQuery() throws HibernateException { public void cancelQuery() throws HibernateException {
errorIfClosed(); errorIfClosed();
getJDBCContext().getConnectionManager().cancelLastQuery(); getTransactionCoordinator().getJdbcCoordinator().cancelLastQuery();
} }
public Interceptor getInterceptor() { public Interceptor getInterceptor() {
@ -1983,23 +1994,17 @@ public final class SessionImpl extends AbstractSessionImpl
} }
public void doWork(Work work) throws HibernateException { public void doWork(Work work) throws HibernateException {
try { transactionCoordinator.getJdbcCoordinator().coordinateWork( work );
work.execute( jdbcContext.getConnectionManager().getConnection() );
jdbcContext.getConnectionManager().afterStatement();
}
catch ( SQLException e ) {
throw factory.getSQLExceptionHelper().convert( e, "error executing work" );
}
} }
public void afterScrollOperation() { public void afterScrollOperation() {
// nothing to do in a stateful session // nothing to do in a stateful session
} }
public JDBCContext getJDBCContext() { @Override
public TransactionCoordinator getTransactionCoordinator() {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); return transactionCoordinator;
return jdbcContext;
} }
public LoadQueryInfluencers getLoadQueryInfluencers() { public LoadQueryInfluencers getLoadQueryInfluencers() {
@ -2098,8 +2103,8 @@ public final class SessionImpl extends AbstractSessionImpl
private void checkTransactionSynchStatus() { private void checkTransactionSynchStatus() {
if ( jdbcContext != null && !isClosed() ) { if ( !isClosed() ) {
jdbcContext.registerSynchronizationIfPossible(); transactionCoordinator.pulse();
} }
} }
@ -2131,7 +2136,7 @@ public final class SessionImpl extends AbstractSessionImpl
listeners = factory.getEventListeners(); listeners = factory.getEventListeners();
if ( isRootSession ) { if ( isRootSession ) {
jdbcContext = JDBCContextImpl.deserialize( ois, this, interceptor ); transactionCoordinator = TransactionCoordinatorImpl.deserialize( ois, this );
} }
persistenceContext = StatefulPersistenceContext.deserialize( ois, this ); persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
@ -2156,7 +2161,7 @@ public final class SessionImpl extends AbstractSessionImpl
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
final SessionImpl child = ( ( SessionImpl ) iter.next() ); final SessionImpl child = ( ( SessionImpl ) iter.next() );
child.rootSession = this; child.rootSession = this;
child.jdbcContext = this.jdbcContext; child.transactionCoordinator = this.transactionCoordinator;
} }
} }
} }
@ -2168,7 +2173,7 @@ public final class SessionImpl extends AbstractSessionImpl
* @throws IOException Indicates a general IO stream exception * @throws IOException Indicates a general IO stream exception
*/ */
private void writeObject(ObjectOutputStream oos) throws IOException { private void writeObject(ObjectOutputStream oos) throws IOException {
if ( !jdbcContext.isReadyForSerialization() ) { if ( ! transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isReadyForSerialization() ) {
throw new IllegalStateException( "Cannot serialize a session while connected" ); throw new IllegalStateException( "Cannot serialize a session while connected" );
} }
@ -2190,7 +2195,7 @@ public final class SessionImpl extends AbstractSessionImpl
factory.serialize( oos ); factory.serialize( oos );
if ( rootSession == null ) { if ( rootSession == null ) {
jdbcContext.serialize( oos ); transactionCoordinator.serialize( oos );
} }
persistenceContext.serialize( oos ); persistenceContext.serialize( oos );
@ -2204,8 +2209,8 @@ public final class SessionImpl extends AbstractSessionImpl
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public Object execute(Callback callback) { public Object execute(LobCreationContext.Callback callback) {
Connection connection = jdbcContext.getConnectionManager().getConnection(); Connection connection = transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getConnection();
try { try {
return callback.executeOnConnection( connection ); return callback.executeOnConnection( connection );
} }
@ -2216,7 +2221,7 @@ public final class SessionImpl extends AbstractSessionImpl
); );
} }
finally { finally {
jdbcContext.getConnectionManager().afterStatement(); transactionCoordinator.getJdbcCoordinator().getLogicalConnection().afterStatementExecution();
} }
} }

View File

@ -21,16 +21,6 @@
*/ */
package org.hibernate.impl; package org.hibernate.impl;
import java.io.Serializable;
import java.sql.Connection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.Criteria; import org.hibernate.Criteria;
@ -50,17 +40,19 @@ import org.hibernate.UnresolvableObjectException;
import org.hibernate.cache.CacheKey; import org.hibernate.cache.CacheKey;
import org.hibernate.collection.PersistentCollection; import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.EntityKey; import org.hibernate.engine.EntityKey;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.NonFlushedChanges;
import org.hibernate.engine.PersistenceContext; import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.StatefulPersistenceContext; import org.hibernate.engine.StatefulPersistenceContext;
import org.hibernate.engine.Versioning; import org.hibernate.engine.Versioning;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.NonFlushedChanges;
import org.hibernate.engine.jdbc.internal.JDBCContextImpl;
import org.hibernate.engine.jdbc.spi.JDBCContext;
import org.hibernate.engine.query.HQLQueryPlan; import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan; import org.hibernate.engine.query.NativeSQLQueryPlan;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification; import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.event.EventListeners; import org.hibernate.event.EventListeners;
import org.hibernate.id.IdentifierGeneratorHelper; import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.loader.criteria.CriteriaLoader; import org.hibernate.loader.criteria.CriteriaLoader;
@ -72,23 +64,42 @@ import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.hibernate.util.CollectionHelper; import org.hibernate.util.CollectionHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.sql.Connection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* @author Gavin King * @author Gavin King
*/ */
public class StatelessSessionImpl extends AbstractSessionImpl public class StatelessSessionImpl extends AbstractSessionImpl implements StatelessSession {
implements JDBCContext.Context, StatelessSession {
private static final Logger log = LoggerFactory.getLogger( StatelessSessionImpl.class ); private static final Logger log = LoggerFactory.getLogger( StatelessSessionImpl.class );
private JDBCContextImpl jdbcContext; private TransactionCoordinator transactionCoordinator;
private PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this ); private PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this );
StatelessSessionImpl(Connection connection, SessionFactoryImpl factory) { StatelessSessionImpl(Connection connection, SessionFactoryImpl factory) {
super( factory ); super( factory );
this.jdbcContext = new JDBCContextImpl( this, connection, EmptyInterceptor.INSTANCE ); this.transactionCoordinator = new TransactionCoordinatorImpl( connection, this );
} }
// TransactionContext ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public TransactionCoordinator getTransactionCoordinator() {
return transactionCoordinator;
}
@Override
public TransactionEnvironment getTransactionEnvironment() {
return factory.getTransactionEnvironment();
}
// inserts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // inserts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -324,22 +335,33 @@ public class StatelessSessionImpl extends AbstractSessionImpl
if ( isClosed() ) { if ( isClosed() ) {
throw new SessionException( "Session was already closed!" ); throw new SessionException( "Session was already closed!" );
} }
jdbcContext.getConnectionManager().close(); transactionCoordinator.close();
setClosed(); setClosed();
} }
public void managedFlush() { public void managedFlush() {
errorIfClosed(); errorIfClosed();
getJDBCContext().getConnectionManager().executeBatch(); getTransactionCoordinator().getJdbcCoordinator().executeBatch();
} }
public boolean shouldAutoClose() { public boolean shouldAutoClose() {
return isAutoCloseSessionEnabled() && !isClosed(); return isAutoCloseSessionEnabled() && !isClosed();
} }
public void afterTransactionCompletion(boolean successful, Transaction tx) {} @Override
public void afterTransactionBegin(TransactionImplementor hibernateTransaction) {
// nothing to do here
}
public void beforeTransactionCompletion(Transaction tx) {} @Override
public void beforeTransactionCompletion(TransactionImplementor hibernateTransaction) {
// nothing to do here
}
@Override
public void afterTransactionCompletion(TransactionImplementor hibernateTransaction, boolean successful) {
// nothing to do here
}
public String bestGuessEntityName(Object object) { public String bestGuessEntityName(Object object) {
if (object instanceof HibernateProxy) { if (object instanceof HibernateProxy) {
@ -350,7 +372,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public Connection connection() { public Connection connection() {
errorIfClosed(); errorIfClosed();
return jdbcContext.borrowConnection(); return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getDistinctConnectionProxy();
} }
public int executeUpdate(String query, QueryParameters queryParameters) public int executeUpdate(String query, QueryParameters queryParameters)
@ -444,11 +466,11 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public boolean isConnected() { public boolean isConnected() {
return jdbcContext.getConnectionManager().isCurrentlyConnected(); return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected();
} }
public boolean isTransactionInProgress() { public boolean isTransactionInProgress() {
return jdbcContext.isTransactionInProgress(); return transactionCoordinator.isTransactionInProgress();
} }
public void setAutoClear(boolean enabled) { public void setAutoClear(boolean enabled) {
@ -465,7 +487,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public Transaction getTransaction() throws HibernateException { public Transaction getTransaction() throws HibernateException {
errorIfClosed(); errorIfClosed();
return jdbcContext.getTransaction(); return transactionCoordinator.getTransaction();
} }
public Transaction beginTransaction() throws HibernateException { public Transaction beginTransaction() throws HibernateException {
@ -517,8 +539,8 @@ public class StatelessSessionImpl extends AbstractSessionImpl
} }
public void afterOperation(boolean success) { public void afterOperation(boolean success) {
if ( !jdbcContext.isTransactionInProgress() ) { if ( ! transactionCoordinator.isTransactionInProgress() ) {
jdbcContext.afterNontransactionalQuery(success); transactionCoordinator.afterNonTransactionalQuery( success );;
} }
} }
@ -619,7 +641,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
throws HibernateException { throws HibernateException {
errorIfClosed(); errorIfClosed();
CustomLoader loader = new CustomLoader( customQuery, getFactory() ); CustomLoader loader = new CustomLoader( customQuery, getFactory() );
return loader.scroll(queryParameters, this); return loader.scroll( queryParameters, this );
} }
public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException { public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
@ -646,10 +668,6 @@ public class StatelessSessionImpl extends AbstractSessionImpl
return null; return null;
} }
public JDBCContext getJDBCContext() {
return jdbcContext;
}
public LoadQueryInfluencers getLoadQueryInfluencers() { public LoadQueryInfluencers getLoadQueryInfluencers() {
return LoadQueryInfluencers.NONE; return LoadQueryInfluencers.NONE;
} }
@ -667,8 +685,6 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public void setFetchProfile(String name) {} public void setFetchProfile(String name) {}
public void afterTransactionBegin(Transaction tx) {}
protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException { protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
// no auto-flushing to support in stateless session // no auto-flushing to support in stateless session
return false; return false;

Some files were not shown because too many files have changed in this diff Show More