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',
// testing
atomikos: 'com.atomikos:transactions-jdbc:3.7.0',
junit: 'junit:junit:3.8.2',
testng: 'org.testng:testng:5.8:jdk15',
jpa_modelgen: 'org.hibernate:hibernate-jpamodelgen:1.1.0.Final',
@ -106,6 +107,7 @@ subprojects { subProject ->
dependencies {
compile( libraries.slf4j_api )
testCompile( libraries.junit )
testCompile( libraries.atomikos )
testRuntime( libraries.slf4j_simple )
testRuntime( libraries.jcl_slf4j )
testRuntime( libraries.jcl_api )
@ -151,12 +153,8 @@ subprojects { subProject ->
sourceCompatibility = "1.6"
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 )
// 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 ->
module.dependencies*.exported = true
}

View File

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

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate;
@ -35,6 +34,9 @@ package org.hibernate;
* @author Gavin King
*/
public class HibernateException extends RuntimeException {
public HibernateException(String s) {
super(s);
}
public HibernateException(Throwable root) {
super(root);
@ -43,10 +45,6 @@ public class HibernateException extends RuntimeException {
public HibernateException(String string, Throwable root) {
super(string, root);
}
public HibernateException(String s) {
super(s);
}
}

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,22 +20,20 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* 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 {
protected String getName() {
return "java:/TransactionManager";
public class ResourceClosedException extends HibernateException {
public ResourceClosedException(String s) {
super( s );
}
public String getUserTransactionName() {
return "java:comp/UserTransaction";
public ResourceClosedException(String string, Throwable root) {
super( string, root );
}
}

View File

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

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,109 +20,140 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate;
import org.hibernate.engine.transaction.spi.LocalStatus;
import javax.transaction.Synchronization;
/**
* Allows the application to define units of work, while
* maintaining abstraction from the underlying transaction
* implementation (eg. JTA, JDBC).<br>
* <br>
* A transaction is associated with a <tt>Session</tt> and is
* usually instantiated by a call to <tt>Session.beginTransaction()</tt>.
* 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 transaction. However, it is intended that there be at most one
* uncommitted <tt>Transaction</tt> associated with a particular
* <tt>Session</tt> at any time.<br>
* <br>
* Implementors are not intended to be threadsafe.
* Defines the contract for abstracting applications from the configured underlying means of transaction management.
* Allows the application to define units of work, while maintaining abstraction from the underlying transaction
* implementation (eg. JTA, JDBC).
* <p/>
* A transaction is associated with a {@link Session} and is usually initiated by a call to
* {@link org.hibernate.Session#beginTransaction()}. 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 transaction. However, it is intended that there be at most one uncommitted transaction associated
* with a particular {@link Session} at any time.
* <p/>
* Implementers are not intended to be thread-safe.
*
* @see Session#beginTransaction()
* @see org.hibernate.transaction.TransactionFactory
* @author Anton van Straaten
* @author Steve Ebersole
*/
public interface Transaction {
/**
* Begin a new transaction.
*/
public void begin() throws HibernateException;
/**
* Flush the associated <tt>Session</tt> and end the unit of work (unless
* we are in {@link FlushMode#MANUAL}.
* </p>
* This method will commit the underlying transaction if and only
* if the underlying transaction was initiated by this object.
* Is this transaction the initiator of any underlying transaction?
*
* @throws HibernateException
* @return {@literal true} if this transaction initiated the underlying transaction; {@literal false} otherwise.
*/
public void commit() throws HibernateException;
public boolean isInitiator();
/**
* Force the underlying transaction to roll back.
* Begin this transaction. No-op if the transaction has already been begun. Note that this is not necessarily
* symmetrical since usually multiple calls to {@link #commit} or {@link #rollback} will error.
*
* @throws HibernateException
* @throws HibernateException Indicates a problem beginning the transaction.
*/
public void rollback() throws HibernateException;
public void begin();
/**
* Was this transaction rolled back or set to rollback only?
* 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 Indicates a problem committing the transaction.
*/
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 actions initiated from this local transaction.
* If, for example, the underlying transaction is forced to rollback via
* some other means, this method still reports false because the rollback
* was not initiated from here.
* 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 boolean True if the transaction was rolled back via this
* local transaction; false otherwise.
* @throws HibernateException
* @return The current local status.
*/
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
* via this local transaction; false otherwise.
* @throws HibernateException
*/
public boolean wasCommitted() throws HibernateException;
public LocalStatus getLocalStatus();
/**
* Is this transaction still active?
* <p/>
* Again, this only returns information in relation to the
* local transaction, not the actual underlying transaction.
* 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 boolean Treu if this local transaction is still active.
* @return {@literal true} if the transaction is still active; {@literal false} otherwise.
*
* @throws HibernateException Indicates a problem checking the transaction status.
*/
public boolean isActive() throws HibernateException;
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?
* <p/>
* Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a
* transaction was rolled back when rollback was performed directly through the JDBC {@link java.sql.Connection},
* only when it was rolled back from here.
*
* @return {@literal true} if the transaction is rolled back; {@literal false} otherwise.
*
* @throws HibernateException Indicates a problem checking the transaction status.
*/
public boolean wasRolledBack();
/**
* Register a user synchronization callback for this transaction.
*
* @param synchronization The Synchronization callback to register.
* @throws HibernateException
*
* @throws HibernateException Indicates a problem registering the synchronization.
*/
public void registerSynchronization(Synchronization synchronization)
throws HibernateException;
public void registerSynchronization(Synchronization synchronization) throws HibernateException;
/**
* Set the transaction timeout for any transaction started by
* a subsequent call to <tt>begin()</tt> on this instance.
* Set the transaction timeout for any transaction started by a subsequent call to {@link #begin} on this instance.
*
* @param seconds The number of seconds before a timeout.
*/
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();
copy.putAll( properties );
ConfigurationHelper.resolvePlaceHolders( copy );
Settings settings = buildSettings( copy, serviceRegistry.getService( JdbcServices.class ) );
Settings settings = buildSettings( copy, serviceRegistry );
return new SessionFactoryImpl(
this,
@ -2825,18 +2825,18 @@ public class Configuration implements Serializable {
*
* @return The build settings
*/
public Settings buildSettings(JdbcServices jdbcServices) {
public Settings buildSettings(ServiceRegistry serviceRegistry) {
Properties clone = ( Properties ) properties.clone();
ConfigurationHelper.resolvePlaceHolders( clone );
return buildSettingsInternal( clone, jdbcServices );
return buildSettingsInternal( clone, serviceRegistry );
}
public Settings buildSettings(Properties props, JdbcServices jdbcServices) throws HibernateException {
return buildSettingsInternal( props, jdbcServices );
public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException {
return buildSettingsInternal( props, serviceRegistry );
}
private Settings buildSettingsInternal(Properties props, JdbcServices jdbcServices) {
final Settings settings = settingsFactory.buildSettings( props, jdbcServices );
private Settings buildSettingsInternal(Properties props, ServiceRegistry serviceRegistry) {
final Settings settings = settingsFactory.buildSettings( props, serviceRegistry );
settings.setEntityTuplizerFactory( this.getEntityTuplizerFactory() );
// settings.setComponentTuplizerFactory( this.getComponentTuplizerFactory() );
return settings;

View File

@ -164,7 +164,7 @@ import org.hibernate.util.ConfigHelper;
* <tr>
* <td><tt>hibernate.transaction.factory_class</tt></td>
* <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>
* <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";
/**
* <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";
/**

View File

@ -23,20 +23,18 @@
*/
package org.hibernate.cfg;
import java.util.Map;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.EntityMode;
import org.hibernate.cache.QueryCacheFactory;
import org.hibernate.cache.RegionFactory;
import org.hibernate.engine.jdbc.JdbcSupport;
import org.hibernate.engine.jdbc.batch.internal.BatchBuilder;
import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.transaction.TransactionManagerLookup;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.tuple.entity.EntityTuplizerFactory;
import java.util.Map;
/**
* Settings that affect the behaviour of Hibernate at runtime.
*
@ -75,9 +73,6 @@ public final class Settings {
private ConnectionReleaseMode connectionReleaseMode;
private RegionFactory regionFactory;
private QueryCacheFactory queryCacheFactory;
private TransactionFactory transactionFactory;
private TransactionManagerLookup transactionManagerLookup;
private BatchBuilder batchBuilder;
private QueryTranslatorFactory queryTranslatorFactory;
private boolean wrapResultSetsEnabled;
private boolean orderUpdatesEnabled;
@ -94,6 +89,8 @@ public final class Settings {
private JdbcSupport jdbcSupport;
private String importFiles;
private JtaPlatform jtaPlatform;
/**
* Package protected constructor
*/
@ -162,10 +159,6 @@ public final class Settings {
return jdbcFetchSize;
}
public TransactionFactory getTransactionFactory() {
return transactionFactory;
}
public String getSessionFactoryName() {
return sessionFactoryName;
}
@ -190,10 +183,6 @@ public final class Settings {
return regionFactory;
}
public TransactionManagerLookup getTransactionManagerLookup() {
return transactionManagerLookup;
}
public boolean isQueryCacheEnabled() {
return queryCacheEnabled;
}
@ -226,10 +215,6 @@ public final class Settings {
return flushBeforeCompletionEnabled;
}
public BatchBuilder getBatchBuilder() {
return batchBuilder;
}
public boolean isAutoCloseSessionEnabled() {
return autoCloseSessionEnabled;
}
@ -349,10 +334,6 @@ public final class Settings {
jdbcFetchSize = integer;
}
void setTransactionFactory(TransactionFactory factory) {
transactionFactory = factory;
}
void setSessionFactoryName(String string) {
sessionFactoryName = string;
}
@ -377,10 +358,6 @@ public final class Settings {
this.regionFactory = regionFactory;
}
void setTransactionManagerLookup(TransactionManagerLookup lookup) {
transactionManagerLookup = lookup;
}
void setQueryCacheEnabled(boolean b) {
queryCacheEnabled = b;
}
@ -413,10 +390,6 @@ public final class Settings {
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
}
void setBatcherBuilder(BatchBuilder batchBuilder) {
this.batchBuilder = batchBuilder;
}
void setAutoCloseSessionEnabled(boolean autoCloseSessionEnabled) {
this.autoCloseSessionEnabled = autoCloseSessionEnabled;
}
@ -496,4 +469,13 @@ public final class Settings {
// void setBytecodeProvider(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.impl.NoCachingRegionFactory;
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.JdbcServices;
import org.hibernate.engine.transaction.spi.TransactionFactory;
import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.transaction.TransactionFactoryFactory;
import org.hibernate.transaction.TransactionManagerLookup;
import org.hibernate.transaction.TransactionManagerLookupFactory;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.service.spi.ServiceRegistry;
import org.hibernate.util.ReflectHelper;
import org.hibernate.util.StringHelper;
@ -66,7 +64,8 @@ public class SettingsFactory implements Serializable {
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();
//SessionFactory name:
@ -90,10 +89,7 @@ public class SettingsFactory implements Serializable {
settings.setJdbcSupport( new JdbcSupport( ! ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, properties ) ) );
// Transaction settings:
TransactionFactory transactionFactory = createTransactionFactory(properties);
settings.setTransactionFactory(transactionFactory);
settings.setTransactionManagerLookup( createTransactionManagerLookup(properties) );
settings.setJtaPlatform( serviceRegistry.getService( JtaPlatform.class ) );
boolean flushBeforeCompletion = ConfigurationHelper.getBoolean(Environment.FLUSH_BEFORE_COMPLETION, properties);
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);
if (batchSize>0) log.info("JDBC batch updates for versioned data: " + enabledDisabled(jdbcBatchVersionedData) );
settings.setJdbcBatchVersionedData(jdbcBatchVersionedData);
settings.setBatcherBuilder( createBatchBuilder(properties, batchSize) );
boolean useScrollableResultSets = ConfigurationHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, meta.supportsScrollableResults());
log.info("Scrollable result sets: " + enabledDisabled(useScrollableResultSets) );
@ -134,7 +129,7 @@ public class SettingsFactory implements Serializable {
log.info( "Connection release mode: " + releaseModeName );
ConnectionReleaseMode releaseMode;
if ( "auto".equals(releaseModeName) ) {
releaseMode = transactionFactory.getDefaultReleaseMode();
releaseMode = serviceRegistry.getService( TransactionFactory.class ).getDefaultReleaseMode();
}
else {
releaseMode = ConnectionReleaseMode.parse( releaseModeName );
@ -301,7 +296,9 @@ public class SettingsFactory implements Serializable {
}
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 ) {
String providerClassName = ConfigurationHelper.getString( Environment.CACHE_PROVIDER, properties, 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.classic.Session;
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.LoggerFactory;
@ -76,7 +77,8 @@ public class JTASessionContext implements CurrentSessionContext {
* {@inheritDoc}
*/
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 ) {
throw new HibernateException( "No TransactionManagerLookup specified" );
}
@ -87,9 +89,9 @@ public class JTASessionContext implements CurrentSessionContext {
if ( txn == null ) {
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
// 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).
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 );
}
final Object txnIdentifier = factory.getSettings().getTransactionManagerLookup() == null
? txn
: factory.getSettings().getTransactionManagerLookup().getTransactionIdentifier( txn );
final Object txnIdentifier = jtaPlatform.getTransactionIdentifier( txn );
Session currentSession = ( Session ) currentSessionMap.get( txnIdentifier );

View File

@ -43,6 +43,10 @@ import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
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
@ -74,11 +78,11 @@ public class ThreadLocalSessionContext implements CurrentSessionContext {
private static final Logger log = LoggerFactory.getLogger( ThreadLocalSessionContext.class );
private static final Class[] SESSION_PROXY_INTERFACES = new Class[] {
org.hibernate.classic.Session.class,
org.hibernate.engine.SessionImplementor.class,
org.hibernate.engine.jdbc.spi.JDBCContext.Context.class,
org.hibernate.event.EventSource.class,
org.hibernate.engine.jdbc.LobCreationContext.class
Session.class,
SessionImplementor.class,
EventSource.class,
TransactionContext.class,
LobCreationContext.class
};
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -265,7 +265,7 @@ public class ActionQueue {
execute( ( Executable ) list.get( i ) );
}
list.clear();
session.getJDBCContext().getConnectionManager().executeBatch();
session.getTransactionCoordinator().getJdbcCoordinator().executeBatch();
}
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.exception.SQLExceptionConverter;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.service.spi.ServiceRegistry;
import org.hibernate.stat.StatisticsImplementor;
import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver;
@ -145,13 +146,6 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
*/
public String getImportedClassName(String name);
/**
* Get the JTA transaction manager
*/
public TransactionManager getTransactionManager();
/**
* Get the default query cache
*/
@ -262,4 +256,5 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
*/
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.ScrollableResults;
import org.hibernate.Transaction;
import org.hibernate.engine.jdbc.spi.JDBCContext;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.event.EventListeners;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.loader.custom.CustomQuery;
@ -157,20 +157,6 @@ public interface SessionImplementor extends Serializable {
*/
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
* not associated with the session
@ -340,11 +326,16 @@ public interface SessionImplementor extends Serializable {
*/
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
* {@link #isOpen()} as this method does not attempt any JTA synch
* Determine whether the session is closed. Provided separately from
* {@link #isOpen()} as this method does not attempt any JTA synchronization
* registration, where as {@link #isOpen()} does; which makes this one
* nicer to use for most internal purposes.
*

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,19 +20,16 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.engine;
import org.hibernate.HibernateException;
import org.hibernate.jdbc.Work;
import java.io.Serializable;
import java.sql.Connection;
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,
* and performing work in a new transaction
@ -41,7 +38,7 @@ import org.hibernate.exception.JDBCExceptionHelper;
*/
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
@ -51,26 +48,27 @@ public abstract class TransactionHelper {
/**
* Suspend the current transaction and perform work in a new transaction
*/
public Serializable doWorkInNewTransaction(final SessionImplementor session)
throws HibernateException {
class Work implements IsolatedWork {
public Serializable doWorkInNewTransaction(final SessionImplementor session) throws HibernateException {
class WorkToDo implements Work {
Serializable generatedValue;
public void doWork(Connection connection) throws HibernateException {
@Override
public void execute(Connection connection) throws SQLException {
String sql = null;
try {
generatedValue = doWorkInCurrentTransaction( connection, sql );
}
catch( SQLException sqle ) {
catch( SQLException e ) {
throw session.getFactory().getSQLExceptionHelper().convert(
sqle,
e,
"could not get or update next value",
sql
);
}
}
}
Work work = new Work();
Isolater.doIsolatedWork( work, session );
WorkToDo work = new WorkToDo();
session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork( work, true );
return work.generatedValue;
}
}

View File

@ -23,19 +23,20 @@
*/
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.SQLException;
import java.util.LinkedHashMap;
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.
*
@ -44,21 +45,20 @@ import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
public abstract class AbstractBatchImpl implements Batch {
private static final Logger log = LoggerFactory.getLogger( AbstractBatchImpl.class );
private final SQLStatementLogger statementLogger;
private final SQLExceptionHelper exceptionHelper;
private Object key;
private final BatchKey key;
private final JdbcCoordinator jdbcCoordinator;
private LinkedHashMap<String,PreparedStatement> statements = new LinkedHashMap<String,PreparedStatement>();
private LinkedHashSet<BatchObserver> observers = new LinkedHashSet<BatchObserver>();
protected AbstractBatchImpl(Object key,
SQLStatementLogger statementLogger,
SQLExceptionHelper exceptionHelper) {
if ( key == null || statementLogger == null || exceptionHelper == null ) {
throw new IllegalArgumentException( "key, statementLogger, and exceptionHelper must be non-null." );
protected AbstractBatchImpl(BatchKey key, JdbcCoordinator jdbcCoordinator) {
if ( key == null ) {
throw new IllegalArgumentException( "batch key cannot be null" );
}
if ( jdbcCoordinator == null ) {
throw new IllegalArgumentException( "JDBC coordinator cannot be null" );
}
this.key = key;
this.statementLogger = statementLogger;
this.exceptionHelper = exceptionHelper;
this.jdbcCoordinator = jdbcCoordinator;
}
/**
@ -74,8 +74,12 @@ public abstract class AbstractBatchImpl implements Batch {
*
* @return The underlying SQLException helper.
*/
protected SQLExceptionHelper getSqlExceptionHelper() {
return exceptionHelper;
protected SQLExceptionHelper sqlExceptionHelper() {
return jdbcCoordinator.getTransactionCoordinator()
.getTransactionContext()
.getTransactionEnvironment()
.getJdbcServices()
.getSqlExceptionHelper();
}
/**
@ -83,8 +87,12 @@ public abstract class AbstractBatchImpl implements Batch {
*
* @return The underlying JDBC services.
*/
protected SQLStatementLogger getSqlStatementLogger() {
return statementLogger;
protected SQLStatementLogger sqlStatementLogger() {
return jdbcCoordinator.getTransactionCoordinator()
.getTransactionContext()
.getTransactionEnvironment()
.getJdbcServices()
.getSqlStatementLogger();
}
/**
@ -96,62 +104,49 @@ public abstract class AbstractBatchImpl implements Batch {
return statements;
}
/**
* {@inheritDoc}
*/
public final Object getKey() {
@Override
public final BatchKey getKey() {
return key;
}
/**
* {@inheritDoc}
*/
@Override
public void addObserver(BatchObserver observer) {
observers.add( observer );
}
/**
* {@inheritDoc}
*/
public final PreparedStatement getBatchStatement(Object key, String sql) {
checkConsistentBatchKey( key );
@Override
public PreparedStatement getBatchStatement(String sql, boolean callable) {
if ( sql == null ) {
throw new IllegalArgumentException( "sql must be non-null." );
}
PreparedStatement statement = statements.get( sql );
if ( statement != null ) {
log.debug( "reusing prepared statement" );
statementLogger.logStatement( sql );
if ( statement == null ) {
statement = buildBatchStatement( sql, callable );
statements.put( sql, statement );
}
else {
log.debug( "reusing batch statement" );
sqlStatementLogger().logStatement( sql );
}
return statement;
}
/**
* {@inheritDoc}
*/
// TODO: should this be final???
private PreparedStatement buildBatchStatement(String sql, boolean callable) {
try {
if ( callable ) {
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
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() {
notifyObserversExplicitExecution();
if ( statements.isEmpty() ) {
@ -162,7 +157,7 @@ public abstract class AbstractBatchImpl implements Batch {
doExecuteBatch();
}
finally {
release();
releaseStatements();
}
}
finally {
@ -176,14 +171,16 @@ public abstract class AbstractBatchImpl implements Batch {
statement.close();
}
catch ( SQLException e ) {
log.error( "unable to release batch statement..." );
log.error( "sqlexception escaped proxy", e );
log.error( "unable to release batch statement; sqlexception escaped proxy", e );
}
}
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 ) {
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.
*/
protected void notifyObserversImplicitExecution() {
protected final void notifyObserversImplicitExecution() {
for ( BatchObserver observer : observers ) {
observer.batchImplicitlyExecuted();
}
}
@Override
public void release() {
if ( getStatements() != null && !getStatements().isEmpty() ) {
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;
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.LoggerFactory;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
import java.util.Map;
/**
* A builder for {@link Batch} instances.
*
* @author Steve Ebersole
*/
public class BatchBuilder {
private static final Logger log = LoggerFactory.getLogger( BatchBuilder.class );
public class BatchBuilderImpl implements BatchBuilder, Configurable {
private static final Logger log = LoggerFactory.getLogger( BatchBuilderImpl.class );
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;
}
@ -52,13 +61,27 @@ public class BatchBuilder {
this.size = size;
}
public Batch buildBatch(Object key,
SQLStatementLogger statementLogger,
SQLExceptionHelper exceptionHelper) {
@Override
public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) {
log.trace( "building batch [size={}]", size );
return size > 1
? new BatchingBatch( key, statementLogger, exceptionHelper, size )
: new NonBatchingBatch( key, statementLogger, exceptionHelper );
? new BatchingBatch( key, jdbcCoordinator, size )
: 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;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
import org.hibernate.jdbc.Expectation;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Map;
/**
* A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does
* batching based on a given size. Once the batch size is reached for a statement
* in the batch, the entire batch is implicitly executed.
* A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does bathing based on a given size. Once
* the batch size is reached for a statement in the batch, the entire batch is implicitly executed.
*
* @author Steve Ebersole
*/
public class BatchingBatch extends AbstractBatchImpl {
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 int batchPosition;
private int statementPosition;
// TODO: A Map is used for expectations so it is possible to track when a batch
// is full (i.e., when the batch for a particular statement exceeds batchSize)
// Until HHH-5797 is fixed, there will only be 1 statement in a batch, so it won't
// be necessary to track expectations by statement.
private Map<String, List<Expectation>> expectationsBySql;
private int maxBatchPosition;
public BatchingBatch(Object key,
SQLStatementLogger statementLogger,
SQLExceptionHelper exceptionHelper,
public BatchingBatch(
BatchKey key,
JdbcCoordinator jdbcCoordinator,
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() ) {
super( key, jdbcCoordinator );
if ( ! key.getExpectation().canBeBatched() ) {
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 {
statement.addBatch();
currentStatement.addBatch();
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getSqlExceptionHelper().convert( e, "could not perform addBatch", sql );
log.debug( "sqlexception escaped proxy", e );
throw sqlExceptionHelper().convert( e, "could not perform addBatch", currentStatementSql );
}
List<Expectation> expectations = expectationsBySql.get( sql );
if ( expectations == null ) {
expectations = new ArrayList<Expectation>( batchSize );
expectationsBySql.put( sql, expectations );
}
expectations.add( expectation );
maxBatchPosition = Math.max( maxBatchPosition, expectations.size() );
// TODO: When HHH-5797 is fixed the following if-block should probably be moved before
// adding the batch to the current statement (to detect that we have finished
// with the previous entity).
if ( maxBatchPosition == batchSize ) {
statementPosition++;
if ( statementPosition >= getKey().getBatchedStatementCount() ) {
batchPosition++;
if ( batchPosition == batchSize ) {
notifyObserversImplicitExecution();
doExecuteBatch();
performExecution();
batchPosition = 0;
}
statementPosition = 0;
}
}
/**
* {@inheritDoc}
*/
@Override
protected void doExecuteBatch() {
if ( maxBatchPosition == 0 ) {
if ( batchPosition == 0 ) {
log.debug( "no batched statements to execute" );
}
else {
if ( log.isDebugEnabled() ) {
log.debug( "Executing {} statements with maximum batch size {} ",
getStatements().size(), maxBatchPosition
);
log.debug( "Executing batch size: " + batchPosition );
}
performExecution();
}
}
private void performExecution() {
try {
executeStatements();
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 ( RuntimeException re ) {
log.error( "Exception executing batch [{}]", re.getMessage() );
throw re;
}
finally {
for ( List<Expectation> expectations : expectationsBySql.values() ) {
expectations.clear();
}
maxBatchPosition = 0;
}
}
}
private void executeStatements() {
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
final String sql = entry.getKey();
final PreparedStatement statement = entry.getValue();
final List<Expectation> expectations = expectationsBySql.get( sql );
if ( batchSize < expectations.size() ) {
throw new IllegalStateException(
"Number of expectations [" + expectations.size() +
"] is greater than batch size [" + batchSize +
"] for statement [" + sql +
"]"
);
}
if ( expectations.size() > 0 ) {
if ( log.isDebugEnabled() ) {
log.debug( "Executing with batch of size {}: {}", expectations.size(), sql );
}
executeStatement( sql, statement, expectations );
expectations.clear();
}
else {
if ( log.isDebugEnabled() ) {
log.debug( "Skipped executing because batch size is 0: ", sql );
}
}
batchPosition = 0;
}
}
private void executeStatement(String sql, PreparedStatement ps, List<Expectation> expectations) {
try {
checkRowCounts( sql, ps.executeBatch(), ps, expectations );
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getSqlExceptionHelper()
.convert( e, "could not execute statement: " + sql );
}
}
private void checkRowCounts(String sql, int[] rowCounts, PreparedStatement ps, List<Expectation> expectations) {
private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException {
int numberOfRowCounts = rowCounts.length;
if ( numberOfRowCounts != expectations.size() ) {
if ( numberOfRowCounts != batchPosition ) {
log.warn( "JDBC driver did not return the expected number of row counts" );
}
try {
for ( int i = 0; i < numberOfRowCounts; i++ ) {
expectations.get( i ).verifyOutcome( rowCounts[i], ps, i );
}
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getSqlExceptionHelper()
.convert( e, "row count verification failed for statement: ", sql );
getKey().getExpectation().verifyOutcome( rowCounts[i], ps, i );
}
}
public void release() {
expectationsBySql.clear();
maxBatchPosition = 0;
}
}

View File

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

View File

@ -42,7 +42,7 @@ public interface Batch {
*
* @return The batch key.
*/
public Object getKey();
public BatchKey getKey();
/**
* Adds an observer to this batch.
@ -52,30 +52,19 @@ public interface Batch {
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.
* @return the prepared statement representing the SQL statement, if the batch contained it;
* null, otherwise.
*/
public PreparedStatement getBatchStatement(Object key, String sql);
/**
* Add a prepared statement to the batch.
* @param callable Is the SQL statement callable?
*
* @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.
*
* @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.

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
*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,29 +20,30 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.batch.spi;
import org.hibernate.jdbc.Expectation;
/**
* Unique key for batch identification.
*
* @author Steve Ebersole
*/
package org.hibernate.transaction;
public interface BatchKey {
/**
* {@link TransactionManagerLookup} strategy for Resin
* How many statements will be in this batch?
* <p/>
* Note that this is distinctly different than the size of the batch.
*
* @author Aapo Laakkonen
* @return The number of statements.
*/
public class ResinTransactionManagerLookup extends JNDITransactionManagerLookup {
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() {
return "java:comp/TransactionManager";
}
/**
* {@inheritDoc}
*/
public String getUserTransactionName() {
return "java:comp/UserTransaction";
}
public Expectation getExpectation();
}

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;
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.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
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
*/
public class LogicalConnectionImpl implements LogicalConnectionImplementor {
private static final Logger log = LoggerFactory.getLogger( LogicalConnectionImpl.class );
private Connection physicalConnection;
private Connection borrowedConnection;
private transient Connection physicalConnection;
private transient Connection shareableConnectionProxy;
private final ConnectionReleaseMode connectionReleaseMode;
private final JdbcServices jdbcServices;
private final StatisticsImplementor statisticsImplementor;
private final JdbcResourceRegistry jdbcResourceRegistry;
private final List<ConnectionObserver> observers = new ArrayList<ConnectionObserver>();
private final transient ConnectionReleaseMode connectionReleaseMode;
private final transient JdbcServices jdbcServices;
private final transient JdbcResourceRegistry jdbcResourceRegistry;
private final transient List<ConnectionObserver> observers;
private boolean releasesEnabled = true;
@ -67,38 +70,39 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
private boolean isClosed;
public LogicalConnectionImpl(Connection userSuppliedConnection,
public LogicalConnectionImpl(
Connection userSuppliedConnection,
ConnectionReleaseMode connectionReleaseMode,
JdbcServices jdbcServices,
StatisticsImplementor statisticsImplementor
) {
this( connectionReleaseMode,
JdbcServices jdbcServices) {
this(
connectionReleaseMode,
jdbcServices,
statisticsImplementor,
userSuppliedConnection != null,
false
(userSuppliedConnection != null),
false,
new ArrayList<ConnectionObserver>()
);
this.physicalConnection = userSuppliedConnection;
}
private LogicalConnectionImpl(ConnectionReleaseMode connectionReleaseMode,
private LogicalConnectionImpl(
ConnectionReleaseMode connectionReleaseMode,
JdbcServices jdbcServices,
StatisticsImplementor statisticsImplementor,
boolean isUserSuppliedConnection,
boolean isClosed) {
boolean isClosed,
List<ConnectionObserver> observers) {
this.connectionReleaseMode = determineConnectionReleaseMode(
jdbcServices, isUserSuppliedConnection, connectionReleaseMode
);
this.jdbcServices = jdbcServices;
this.statisticsImplementor = statisticsImplementor;
this.jdbcResourceRegistry =
new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() );
this.jdbcResourceRegistry = new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() );
this.observers = observers;
this.isUserSuppliedConnection = isUserSuppliedConnection;
this.isClosed = isClosed;
}
private static ConnectionReleaseMode determineConnectionReleaseMode(JdbcServices jdbcServices,
private static ConnectionReleaseMode determineConnectionReleaseMode(
JdbcServices jdbcServices,
boolean isUserSuppliedConnection,
ConnectionReleaseMode connectionReleaseMode) {
if ( isUserSuppliedConnection ) {
@ -114,60 +118,37 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
}
}
/**
* {@inheritDoc}
*/
@Override
public JdbcServices getJdbcServices() {
return jdbcServices;
}
/**
* {@inheritDoc}
*/
public StatisticsImplementor getStatisticsImplementor() {
return statisticsImplementor;
}
/**
* {@inheritDoc}
*/
@Override
public JdbcResourceRegistry getResourceRegistry() {
return jdbcResourceRegistry;
}
/**
* {@inheritDoc}
*/
@Override
public void addObserver(ConnectionObserver observer) {
observers.add( observer );
}
/**
* {@inheritDoc}
*/
@Override
public void removeObserver(ConnectionObserver connectionObserver) {
observers.remove( connectionObserver );
}
@Override
public boolean isOpen() {
return !isClosed;
}
/**
* {@inheritDoc}
*/
public boolean isLogicallyConnected() {
return isUserSuppliedConnection ?
isPhysicallyConnected() :
isOpen();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isPhysicallyConnected() {
return physicalConnection != null;
}
/**
* {@inheritDoc}
*/
@Override
public Connection getConnection() throws HibernateException {
if ( isClosed ) {
throw new HibernateException( "Logical connection is closed" );
@ -182,16 +163,33 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
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}
*/
public Connection close() {
Connection c = physicalConnection;
try {
releaseBorrowedConnection();
log.trace( "closing logical connection" );
if ( !isUserSuppliedConnection && physicalConnection != null ) {
Connection c = isUserSuppliedConnection ? physicalConnection : null;
try {
releaseProxies();
jdbcResourceRegistry.close();
if ( !isUserSuppliedConnection && physicalConnection != null ) {
releaseConnection();
}
return c;
@ -204,46 +202,28 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
for ( ConnectionObserver observer : observers ) {
observer.logicalConnectionClosed();
}
observers.clear();
}
}
/**
* {@inheritDoc}
*/
private void releaseProxies() {
if ( shareableConnectionProxy != null ) {
try {
shareableConnectionProxy.close();
}
catch (SQLException e) {
log.debug( "Error releasing shared connection proxy", e );
}
}
shareableConnectionProxy = null;
}
@Override
public ConnectionReleaseMode getConnectionReleaseMode() {
return connectionReleaseMode;
}
public boolean hasBorrowedConnection() {
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;
}
}
}
@Override
public void afterStatementExecution() {
log.trace( "starting after statement execution processing [{}]", connectionReleaseMode );
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
@ -255,13 +235,11 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
log.debug( "skipping aggressive release due to registered resources" );
return;
}
else if ( borrowedConnection != null ) {
log.debug( "skipping aggresive-release due to borrowed connection" );
}
releaseConnection();
}
}
@Override
public void afterTransaction() {
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ||
connectionReleaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
@ -273,20 +251,21 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
}
}
@Override
public void disableReleases() {
log.trace( "disabling releases" );
releasesEnabled = false;
}
@Override
public void enableReleases() {
log.trace( "(re)enabling releases" );
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() {
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
*/
@ -349,32 +328,32 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
for ( ConnectionObserver observer : observers ) {
observer.physicalConnectionReleased();
}
releaseNonDurableObservers();
}
/**
* 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 ( isClosed ) {
throw new IllegalStateException( "cannot manually disconnect because logical connection is already closed" );
}
releaseProxies();
Connection c = physicalConnection;
jdbcResourceRegistry.releaseResources();
releaseConnection();
return c;
}
/**
* Manually reconnect the underlying JDBC Connection. Should be called at
* some point after manualDisconnect().
* <p/>
* This form is used for user-supplied connections.
*/
public void reconnect(Connection suppliedConnection) {
private void releaseNonDurableObservers() {
Iterator observers = this.observers.iterator();
while ( observers.hasNext() ) {
if ( NonDurableConnectionObserver.class.isInstance( observers.next() ) ) {
observers.remove();
}
}
}
@Override
public void manualReconnect(Connection suppliedConnection) {
if ( isClosed ) {
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() {
return isUserSuppliedConnection ?
! isPhysicallyConnected() :
! getResourceRegistry().hasRegisteredResources()
;
return isUserSuppliedConnection
? ! isPhysicallyConnected()
: ! getResourceRegistry().hasRegisteredResources();
}
public void serialize(ObjectOutputStream oos) throws IOException {
oos.writeBoolean( isUserSuppliedConnection );
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,
JdbcServices jdbcServices,
StatisticsImplementor statisticsImplementor,
ConnectionReleaseMode connectionReleaseMode
) throws IOException {
public static LogicalConnectionImpl deserialize(
ObjectInputStream ois,
TransactionContext transactionContext) throws IOException, ClassNotFoundException {
boolean isUserSuppliedConnection = ois.readBoolean();
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(
connectionReleaseMode,
jdbcServices,
statisticsImplementor,
ois.readBoolean(),
ois.readBoolean()
transactionContext.getConnectionReleaseMode(),
transactionContext.getTransactionEnvironment().getJdbcServices(),
isUserSuppliedConnection,
isClosed,
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.LoggerFactory;
import org.hibernate.TransactionException;
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.stat.StatisticsImplementor;
import org.hibernate.engine.jdbc.spi.NonDurableConnectionObserver;
/**
* The {@link InvocationHandler} for intercepting messages to {@link java.sql.Connection} proxies.
*
* @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 LogicalConnectionImplementor logicalConnection;
@ -112,6 +112,10 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
return null;
}
if ( "isClosed".equals( methodName ) ) {
return ! isValid();
}
errorIfInvalid();
// 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 {
if ( getStatisticsImplementorOrNull() != null ) {
getStatisticsImplementorOrNull().prepareStatement();
}
logicalConnection.notifyObserversStatementPrepared();
postProcessStatement( statement );
}
@ -203,29 +205,25 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
invalidate();
}
/**
* {@inheritDoc}
*/
// ConnectionObserver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public void physicalConnectionObtained(Connection connection) {
}
/**
* {@inheritDoc}
*/
@Override
public void physicalConnectionReleased() {
log.info( "logical connection releasing its physical connection");
}
/**
* {@inheritDoc}
*/
@Override
public void logicalConnectionClosed() {
log.info( "*** logical connection closed ***" );
invalidateHandle();
}
/* package-protected */
StatisticsImplementor getStatisticsImplementorOrNull() {
return getLogicalConnection().getStatisticsImplementor();
@Override
public void statementPrepared() {
// N/A
}
}

View File

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

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,23 +20,28 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.jdbc;
package org.hibernate.engine.jdbc.spi;
import java.sql.Connection;
/**
* Interface implemented by JDBC connection wrappers in order to give
* access to the underlying wrapped connection.
*
* @author Steve Ebersole
*/
public interface ConnectionWrapper {
/**
* Get a reference to the wrapped connection.
*
* @return The wrapped connection.
*/
public Connection getWrappedConnection();
public class ConnectionObserverAdapter implements ConnectionObserver {
@Override
public void physicalConnectionObtained(Connection connection) {
}
@Override
public void physicalConnectionReleased() {
}
@Override
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
*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,35 +20,32 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.spi;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.engine.SessionFactoryImplementor;
import java.io.Serializable;
/**
* Access to services needed in the context of processing JDBC requests.
*
* @author Steve Ebersole
*/
package org.hibernate.transaction;
public interface JdbcContext extends Serializable {
public SessionFactoryImplementor getSessionFactory();
public ConnectionReleaseMode getConnectionReleaseMode();
/**
* {@link TransactionManagerLookup} strategy for Orion
*
* @author Gavin King
*/
public class OrionTransactionManagerLookup extends JNDITransactionManagerLookup {
public boolean isClosed();
/**
* {@inheritDoc}
*/
protected String getName() {
return "java:comp/UserTransaction";
public boolean isFlushModeNever();
public boolean isFlushBeforeCompletionEnabled();
public void managedFlush();
public boolean shouldAutoClose();
public void managedClose();
}
/**
* {@inheritDoc}
*/
public String getUserTransactionName() {
return "java:comp/UserTransaction";
}
}

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;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.Statement;
@ -31,7 +32,7 @@ import java.sql.Statement;
*
* @author Steve Ebersole
*/
public interface JdbcResourceRegistry {
public interface JdbcResourceRegistry extends Serializable {
/**
* Register a JDBC statement.
*

View File

@ -31,7 +31,7 @@ import java.sql.Connection;
*
* @author Steve Ebersole
*/
public interface LogicalConnection {
public interface LogicalConnection extends Serializable {
/**
* Is this logical connection open? Another phraseology sometimes used is: "are we
* logically connected"?
@ -55,10 +55,27 @@ public interface LogicalConnection {
* connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
* or has previously been aggressively released.
*
* @todo ?? Move this to {@link LogicalConnectionImplementor} in lieu of {@link #getShareableConnectionProxy} and {@link #getDistinctConnectionProxy} ??
*
* @return The current Connection.
*/
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
* with this logical connection.
@ -68,4 +85,6 @@ public interface LogicalConnection {
* @return The physical connection which was being used.
*/
public Connection close();
public void afterTransaction();
}

View File

@ -24,8 +24,11 @@
package org.hibernate.engine.jdbc.spi;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler;
import org.hibernate.stat.StatisticsImplementor;
import java.sql.Connection;
/**
* The "internal" contract for LogicalConnection
*
@ -39,13 +42,6 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
*/
public JdbcServices getJdbcServices();
/**
* Obtains the statistics implementor.
*
* @return the statistics implementor
*/
public StatisticsImplementor getStatisticsImplementor();
/**
* Obtains the JDBC resource registry associated with this logical connection.
*
@ -60,6 +56,13 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
*/
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.
*
@ -91,5 +94,26 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
*/
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
*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,23 +20,14 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* 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 {
protected String getName() {
return "java:/TransactionManager";
}
public String getUserTransactionName() {
return "UserTransaction";
}
public interface NonDurableConnectionObserver extends ConnectionObserver {
}

View File

@ -23,6 +23,7 @@
*/
package org.hibernate.engine.jdbc.spi;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLWarning;
@ -41,7 +42,7 @@ import org.hibernate.util.StringHelper;
*
* @author Steve Ebersole
*/
public class SQLExceptionHelper {
public class SQLExceptionHelper implements Serializable {
private static final Logger log = LoggerFactory.getLogger( SQLExceptionHelper.class );
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 );
String sql = queryParameters.getFilteredSQL();
ps = session.getJDBCContext().getConnectionManager().prepareStatement( sql, false );
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
try {
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
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.transaction;
package org.hibernate.engine.transaction.internal;
import org.hibernate.HibernateException;
/**
* TODO : javadoc
* Indicates an attempt to register a null synchronization. Basically a glorified {@link NullPointerException}
*
* @author Steve Ebersole
*/

View File

@ -1,7 +1,7 @@
/*
* 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
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -21,7 +21,9 @@
* 51 Franklin Street, Fifth Floor
* 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 javax.transaction.Synchronization;
@ -29,25 +31,17 @@ import javax.transaction.Synchronization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
/**
* Manages a registry of {@link Synchronization Synchronizations}.
*
* @author Steve Ebersole
*/
public class SynchronizationRegistry {
private static final Logger log = LoggerFactory.getLogger( SynchronizationRegistry.class );
public class SynchronizationRegistryImpl implements SynchronizationRegistry {
private static final Logger log = LoggerFactory.getLogger( SynchronizationRegistryImpl.class );
private LinkedHashSet<Synchronization> synchronizations;
/**
* Register a user {@link Synchronization} callback for this transaction.
*
* @param synchronization The synchronization callback to register.
*
* @throws HibernateException
*/
@Override
public void registerSynchronization(Synchronization synchronization) {
if ( synchronization == null ) {
throw new NullSynchronizationException();
@ -63,10 +57,7 @@ public class SynchronizationRegistry {
}
}
/**
* Delegate {@link Synchronization#beforeCompletion} calls to {@link #registerSynchronization registered}
* {@link Synchronization Synchronizations}
*/
@Override
public void notifySynchronizationsBeforeTransactionCompletion() {
if ( synchronizations != null ) {
for ( Synchronization synchronization : synchronizations ) {
@ -80,12 +71,7 @@ public class SynchronizationRegistry {
}
}
/**
* Delegate {@link Synchronization#afterCompletion} calls to {@link #registerSynchronization registered}
* {@link Synchronization Synchronizations}
*
* @param status The transaction status (if known) per {@link javax.transaction.Status}
*/
@Override
public void notifySynchronizationsAfterTransactionCompletion(int status) {
if ( synchronizations != null ) {
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
*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,60 +20,64 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.transaction;
import java.util.Properties;
package org.hibernate.engine.transaction.internal.jta;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Transaction;
import org.hibernate.TransactionException;
import org.hibernate.engine.jdbc.spi.JDBCContext;
import org.hibernate.util.JTAHelper;
import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionFactory;
import javax.transaction.SystemException;
/**
* Factory for {@link CMTTransaction} instances.
* Factory for Container Managed Transaction (CMT) based transaction facades.
*
* @author Steve Ebersole
* @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() {
return ConnectionReleaseMode.AFTER_STATEMENT;
}
public void configure(Properties props) throws HibernateException {}
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
throws HibernateException {
return new CMTTransaction(jdbcContext, transactionContext);
}
public boolean isTransactionManagerRequired() {
@Override
public boolean compatibleWithJtaSynchronization() {
return true;
}
public boolean areCallbacksLocalToHibernateTransactions() {
return false;
}
public boolean isTransactionInProgress(
JDBCContext jdbcContext,
Context transactionContext,
Transaction transaction) {
@Override
public boolean isJoinableJtaTransaction(TransactionCoordinator transactionCoordinator, CMTTransaction transaction) {
try {
return JTAHelper.isTransactionInProgress(
transactionContext.getFactory().getTransactionManager().getTransaction()
);
final int status = transactionCoordinator
.getTransactionContext()
.getTransactionEnvironment()
.getJtaPlatform()
.retrieveTransactionManager()
.getStatus();
return JtaStatusHelper.isActive( status );
}
catch( SystemException 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
*
* 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
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor
* 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.SystemException;
@ -31,7 +31,7 @@ import javax.transaction.UserTransaction;
import org.hibernate.TransactionException;
/**
* Utility for dealing with JTA statses.
* Utility for dealing with JTA statuses.
*
* @author Steve Ebersole
*/
@ -49,7 +49,7 @@ public class JtaStatusHelper {
try {
final int status = userTransaction.getStatus();
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;
}
@ -97,7 +97,7 @@ public class JtaStatusHelper {
*
* @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) {
final int status = getStatus( userTransaction );
@ -109,7 +109,7 @@ public class JtaStatusHelper {
*
* @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) {
return isActive( getStatus( transactionManager ) );
@ -133,7 +133,7 @@ public class JtaStatusHelper {
*
* @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) {
return isRollback( getStatus( userTransaction ) );
@ -144,7 +144,7 @@ public class JtaStatusHelper {
*
* @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) {
return isRollback( getStatus( transactionManager ) );
@ -158,9 +158,7 @@ public class JtaStatusHelper {
* @return True if the code indicates a roll back; false otherwise.
*/
public static boolean isCommitted(int status) {
return status == Status.STATUS_MARKED_ROLLBACK ||
status == Status.STATUS_ROLLING_BACK ||
status == Status.STATUS_ROLLEDBACK;
return status == Status.STATUS_COMMITTED;
}
/**
@ -168,7 +166,7 @@ public class JtaStatusHelper {
*
* @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) {
return isCommitted( getStatus( userTransaction ) );
@ -179,7 +177,7 @@ public class JtaStatusHelper {
*
* @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) {
return isCommitted( getStatus( transactionManager ) );
@ -192,6 +190,7 @@ public class JtaStatusHelper {
*
* @return True if the code indicates a roll back; false otherwise.
*/
@SuppressWarnings( {"UnusedDeclaration"})
public static boolean isMarkedForRollback(int status) {
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
*
* 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
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -21,15 +21,16 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.transaction.synchronization;
import org.hibernate.transaction.TransactionFactory;
package org.hibernate.engine.transaction.spi;
/**
* TODO : javadoc
* See the JPA notion of joining a transaction for details.
*
* @author Emmanuel Bernard
* @author Steve Ebersole
*/
public interface AfterCompletionAction {
public void doAction(TransactionFactory.Context ctx, int status);
public enum JoinStatus {
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
*
* 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
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -21,26 +21,26 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.transaction.synchronization;
import javax.transaction.Synchronization;
package org.hibernate.engine.transaction.synchronization.internal;
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
import org.slf4j.Logger;
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
*/
public class HibernateSynchronizationImpl implements Synchronization {
private static final Logger log = LoggerFactory.getLogger( HibernateSynchronizationImpl.class );
public class RegisteredSynchronization implements Synchronization {
private static final Logger log = LoggerFactory.getLogger( RegisteredSynchronization.class );
private final CallbackCoordinator coordinator;
private final SynchronizationCallbackCoordinator synchronizationCallbackCoordinator;
public HibernateSynchronizationImpl(CallbackCoordinator coordinator) {
this.coordinator = coordinator;
public RegisteredSynchronization(SynchronizationCallbackCoordinator synchronizationCallbackCoordinator) {
this.synchronizationCallbackCoordinator = synchronizationCallbackCoordinator;
}
/**
@ -48,7 +48,7 @@ public class HibernateSynchronizationImpl implements Synchronization {
*/
public void beforeCompletion() {
log.trace( "JTA sync : beforeCompletion()" );
coordinator.beforeCompletion();
synchronizationCallbackCoordinator.beforeCompletion();
}
/**
@ -56,6 +56,6 @@ public class HibernateSynchronizationImpl implements Synchronization {
*/
public void afterCompletion(int 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
*
* 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
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -21,75 +21,57 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.transaction.synchronization;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
package org.hibernate.engine.transaction.synchronization.internal;
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.LoggerFactory;
import org.hibernate.TransactionException;
import org.hibernate.engine.jdbc.spi.JDBCContext;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.util.JTAHelper;
import javax.transaction.SystemException;
/**
* Manages callbacks from the {@link javax.transaction.Synchronization} registered by Hibernate.
*
* @author Steve Ebersole
*/
public class CallbackCoordinator {
private static final Logger log = LoggerFactory.getLogger( CallbackCoordinator.class );
public class SynchronizationCallbackCoordinatorImpl implements SynchronizationCallbackCoordinator {
private static final Logger log = LoggerFactory.getLogger( SynchronizationCallbackCoordinatorImpl.class );
private final TransactionFactory.Context ctx;
private JDBCContext jdbcContext;
private final Transaction jtaTransaction;
private final org.hibernate.Transaction hibernateTransaction;
private final TransactionCoordinator transactionCoordinator;
private BeforeCompletionManagedFlushChecker beforeCompletionManagedFlushChecker;
private ManagedFlushChecker managedFlushChecker;
private AfterCompletionAction afterCompletionAction;
private ExceptionMapper exceptionMapper;
public CallbackCoordinator(
TransactionFactory.Context ctx,
JDBCContext jdbcContext,
Transaction jtaTransaction,
org.hibernate.Transaction hibernateTransaction) {
this.ctx = ctx;
this.jdbcContext = jdbcContext;
this.jtaTransaction = jtaTransaction;
this.hibernateTransaction = hibernateTransaction;
public SynchronizationCallbackCoordinatorImpl(TransactionCoordinator transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator;
reset();
}
public void reset() {
beforeCompletionManagedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER;
managedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER;
exceptionMapper = STANDARD_EXCEPTION_MAPPER;
afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION;
}
public BeforeCompletionManagedFlushChecker getBeforeCompletionManagedFlushChecker() {
return beforeCompletionManagedFlushChecker;
}
public void setBeforeCompletionManagedFlushChecker(BeforeCompletionManagedFlushChecker beforeCompletionManagedFlushChecker) {
this.beforeCompletionManagedFlushChecker = beforeCompletionManagedFlushChecker;
}
public ExceptionMapper getExceptionMapper() {
return exceptionMapper;
@Override
public void setManagedFlushChecker(ManagedFlushChecker managedFlushChecker) {
this.managedFlushChecker = managedFlushChecker;
}
@Override
public void setExceptionMapper(ExceptionMapper exceptionMapper) {
this.exceptionMapper = exceptionMapper;
}
public AfterCompletionAction getAfterCompletionAction() {
return afterCompletionAction;
}
@Override
public void setAfterCompletionAction(AfterCompletionAction afterCompletionAction) {
this.afterCompletionAction = afterCompletionAction;
}
@ -102,7 +84,12 @@ public class CallbackCoordinator {
boolean flush;
try {
flush = beforeCompletionManagedFlushChecker.shouldDoManagedFlush( ctx, jtaTransaction );
final int status = transactionCoordinator
.getTransactionContext()
.getTransactionEnvironment()
.getJtaPlatform()
.getCurrentStatus();
flush = managedFlushChecker.shouldDoManagedFlush( transactionCoordinator, status );
}
catch ( SystemException se ) {
setRollbackOnly();
@ -112,7 +99,7 @@ public class CallbackCoordinator {
try {
if ( flush ) {
log.trace( "automatically flushing session" );
ctx.managedFlush();
transactionCoordinator.getTransactionContext().managedFlush();
}
}
catch ( RuntimeException re ) {
@ -120,48 +107,41 @@ public class CallbackCoordinator {
throw exceptionMapper.mapManagedFlushFailure( "error during managed flush", re );
}
finally {
jdbcContext.beforeTransactionCompletion( hibernateTransaction );
transactionCoordinator.sendBeforeTransactionCompletionNotifications( null );
transactionCoordinator.getTransactionContext().beforeTransactionCompletion( null );
}
}
private void setRollbackOnly() {
try {
jtaTransaction.setRollbackOnly();
}
catch ( SystemException se ) {
// best effort
log.error( "could not set transaction to rollback only", se );
}
transactionCoordinator.setRollbackOnly();
}
public void afterCompletion(int status) {
log.trace( "transaction after completion callback [status={}]", status );
try {
afterCompletionAction.doAction( ctx, status );
final boolean wasSuccessful = ( status == Status.STATUS_COMMITTED );
jdbcContext.afterTransactionCompletion( wasSuccessful, hibernateTransaction );
afterCompletionAction.doAction( transactionCoordinator, status );
transactionCoordinator.afterTransaction( null, status );
}
finally {
reset();
jdbcContext.cleanUpJtaSynchronizationCallbackCoordinator();
if ( ctx.shouldAutoClose() && !ctx.isClosed() ) {
if ( transactionContext().shouldAutoClose() && ! transactionContext().isClosed() ) {
log.trace( "automatically closing session" );
ctx.managedClose();
transactionContext().managedClose();
}
}
}
private static final BeforeCompletionManagedFlushChecker STANDARD_MANAGED_FLUSH_CHECKER = new BeforeCompletionManagedFlushChecker() {
public boolean shouldDoManagedFlush(TransactionFactory.Context ctx, Transaction jtaTransaction)
throws SystemException {
return !ctx.isClosed() &&
!ctx.isFlushModeNever() &&
ctx.isFlushBeforeCompletionEnabled() &&
!JTAHelper.isRollback( jtaTransaction.getStatus() );
//actually, this last test is probably unnecessary, since
//beforeCompletion() doesn't get called during rollback
private TransactionContext transactionContext() {
return transactionCoordinator.getTransactionContext();
}
private static final ManagedFlushChecker STANDARD_MANAGED_FLUSH_CHECKER = new ManagedFlushChecker() {
@Override
public boolean shouldDoManagedFlush(TransactionCoordinator coordinator, int jtaStatus) {
return coordinator.getTransactionContext().isFlushModeNever() &&
coordinator.getTransactionContext().isFlushBeforeCompletionEnabled() &&
!JtaStatusHelper.isRollback( jtaStatus );
}
};
@ -178,7 +158,8 @@ public class CallbackCoordinator {
};
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.
}
};

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
*
* 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
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -21,18 +21,20 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.transaction.synchronization;
package org.hibernate.engine.transaction.synchronization.spi;
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
*/
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 systemException The causal exception

View File

@ -1,7 +1,7 @@
/*
* 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
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -21,31 +21,27 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.transaction.synchronization;
package org.hibernate.engine.transaction.synchronization.spi;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.transaction.TransactionFactory;
import java.io.Serializable;
/**
* Contract for checking whether to perform a managed flush in a
* {@link javax.transaction.Synchronization#beforeCompletion()} callback
* A pluggable strategy for defining how the {@link javax.transaction.Synchronization} registered by Hibernate determines
* 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
*/
public interface BeforeCompletionManagedFlushChecker {
public interface ManagedFlushChecker extends Serializable {
/**
* Check whether we should perform the managed flush
*
* @param ctx The Hibernate "transaction context"
* @param jtaTransaction The JTA transaction
* @param coordinator The transaction coordinator
* @param jtaStatus The status of the current JTA transaction.
*
* @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)
throws SystemException;
public boolean shouldDoManagedFlush(TransactionCoordinator coordinator, int jtaStatus);
}

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");
try {
session.getJDBCContext().getConnectionManager().flushBeginning();
session.getTransactionCoordinator().getJdbcCoordinator().flushBeginning();
// we need to lock the collection caches before
// executing entity inserts/updates in order to
// account for bidi associations
@ -325,7 +325,7 @@ public abstract class AbstractFlushingEventListener implements Serializable {
throw he;
}
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();
boolean inTxn = source.getJDBCContext().isTransactionInProgress();
boolean inTxn = source.getTransactionCoordinator().isTransactionInProgress();
boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
// 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 java.io.Serializable;
import java.sql.SQLException;
/**
@ -42,9 +43,9 @@ import java.sql.SQLException;
* @author Steve Ebersole
* @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 message An optional error message.

View File

@ -23,35 +23,33 @@
*/
package org.hibernate.hql.ast.exec;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.List;
import java.util.Collections;
import antlr.RecognitionException;
import antlr.collections.AST;
import org.hibernate.HibernateException;
import org.hibernate.action.BulkOperationCleanupAction;
import org.hibernate.engine.SessionFactoryImplementor;
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.hql.ast.HqlSqlWalker;
import org.hibernate.hql.ast.SqlGenerator;
import org.hibernate.jdbc.Work;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.InsertSelect;
import org.hibernate.sql.Select;
import org.hibernate.sql.SelectFragment;
import org.hibernate.util.JDBCExceptionReporter;
import org.hibernate.util.StringHelper;
import antlr.RecognitionException;
import antlr.collections.AST;
import org.slf4j.Logger;
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.
*
@ -139,11 +137,15 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
" from " + persister.getTemporaryIdTableName();
}
protected void createTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
// 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
IsolatedWork work = new IsolatedWork() {
public void doWork(Connection connection) throws HibernateException {
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 {
@ -160,21 +162,30 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
}
}
catch( Exception e ) {
log.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
LOG.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
}
}
};
}
protected void createTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
// 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
TemporaryTableCreationWork work = new TemporaryTableCreationWork( persister );
if ( shouldIsolateTemporaryTableDDL() ) {
if ( getFactory().getSettings().isDataDefinitionInTransactionSupported() ) {
Isolater.doIsolatedWork( work, session );
session.getTransactionCoordinator()
.getTransaction()
.createIsolationDelegate()
.delegateWork( work, getFactory().getSettings().isDataDefinitionInTransactionSupported() );
}
else {
Isolater.doNonTransactedWork( work, session );
}
}
else {
work.doWork( session.getJDBCContext().getConnectionManager().getConnection() );
session.getJDBCContext().getConnectionManager().afterStatement();
final Connection connection = session.getTransactionCoordinator()
.getJdbcCoordinator()
.getLogicalConnection()
.getShareableConnectionProxy();
work.execute( connection );
session.getTransactionCoordinator()
.getJdbcCoordinator()
.getLogicalConnection()
.afterStatementExecution();
}
}
@ -194,10 +205,17 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
}
};
protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) {
IsolatedWork work = new IsolatedWork() {
public void doWork(Connection connection) throws HibernateException {
private static class TemporaryTableDropWork implements Work {
private final Queryable persister;
private final SessionImplementor session;
private TemporaryTableDropWork(Queryable persister, SessionImplementor session) {
this.persister = persister;
this.session = session;
}
@Override
public void execute(Connection connection) {
final String command = session.getFactory().getDialect().getDropTemporaryTableString()
+ ' ' + persister.getTemporaryIdTableName();
try {
@ -216,31 +234,38 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
}
}
catch( Exception e ) {
log.warn( "unable to drop temporary id table after use [" + e.getMessage() + "]" );
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() ) {
if ( getFactory().getSettings().isDataDefinitionInTransactionSupported() ) {
Isolater.doIsolatedWork( work, session );
session.getTransactionCoordinator()
.getTransaction()
.createIsolationDelegate()
.delegateWork( work, getFactory().getSettings().isDataDefinitionInTransactionSupported() );
}
else {
Isolater.doNonTransactedWork( work, session );
}
}
else {
work.doWork( session.getJDBCContext().getConnectionManager().getConnection() );
session.getJDBCContext().getConnectionManager().afterStatement();
final Connection connection = session.getTransactionCoordinator()
.getJdbcCoordinator()
.getLogicalConnection()
.getShareableConnectionProxy();
work.execute( connection );
session.getTransactionCoordinator()
.getJdbcCoordinator()
.getLogicalConnection()
.afterStatementExecution();
}
}
else {
// at the very least cleanup the data :)
PreparedStatement ps = null;
try {
ps = session.getJDBCContext().getConnectionManager().prepareStatement( "delete from " + persister.getTemporaryIdTableName(),
false
);
final String sql = "delete from " + persister.getTemporaryIdTableName();
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
ps.executeUpdate();
}
catch( Throwable t ) {

View File

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

View File

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

View File

@ -129,7 +129,7 @@ public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
int resultCount = 0;
try {
try {
ps = session.getJDBCContext().getConnectionManager().prepareStatement( idInsertSelect, false );
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( idInsertSelect, false );
// int parameterStart = getWalker().getNumberOfParametersInSetClause();
// List allParams = getIdSelectParameterSpecifications();
// Iterator whereParams = allParams.subList( parameterStart, allParams.size() ).iterator();
@ -161,7 +161,7 @@ public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
}
try {
try {
ps = session.getJDBCContext().getConnectionManager().prepareStatement( updates[i], false );
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( updates[i], false );
if ( hqlParameters[i] != null ) {
int position = 1; // jdbc params are 1-based
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();
try {
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement(sql);
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try {
ResultSet rs = st.executeQuery();
final String result;

View File

@ -87,7 +87,10 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
}
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 {
@ -131,7 +134,10 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
}
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 {

View File

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

View File

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

View File

@ -96,7 +96,7 @@ public class SequenceIdentityGenerator extends SequenceGenerator
}
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 {

View File

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

View File

@ -50,7 +50,10 @@ public abstract class AbstractSelectingDelegate implements InsertGeneratedIdenti
public final Serializable performInsert(String insertSQL, SessionImplementor session, Binder binder) {
try {
// 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 {
binder.bindValues( insert );
insert.executeUpdate();
@ -71,7 +74,10 @@ public abstract class AbstractSelectingDelegate implements InsertGeneratedIdenti
try {
//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 {
bindParameters( session, idSelect, binder.getEntity() );
ResultSet rs = idSelect.executeQuery();

View File

@ -38,6 +38,8 @@ import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
import java.util.List;
@ -46,7 +48,7 @@ import java.util.List;
*
* @author Gavin King
*/
public abstract class AbstractSessionImpl implements SessionImplementor {
public abstract class AbstractSessionImpl implements SessionImplementor, TransactionContext {
protected transient SessionFactoryImpl factory;
private boolean closed = false;
@ -59,6 +61,11 @@ public abstract class AbstractSessionImpl implements SessionImplementor {
return factory;
}
@Override
public TransactionEnvironment getTransactionEnvironment() {
return factory.getTransactionEnvironment();
}
public boolean isClosed() {
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;
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.Cache;
import org.hibernate.ConnectionReleaseMode;
@ -76,10 +50,6 @@ import org.hibernate.cache.impl.CacheDataDescriptionImpl;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
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.JTASessionContext;
import org.hibernate.context.ManagedSessionContext;
@ -92,12 +62,16 @@ import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.engine.NamedSQLQueryDefinition;
import org.hibernate.engine.ResultSetMappingDefinition;
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.Fetch;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.query.QueryPlanCache;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
import org.hibernate.event.EventListeners;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDGenerator;
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.pretty.MessageHelper;
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.stat.ConcurrentStatisticsImpl;
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.SchemaUpdate;
import org.hibernate.tool.hbm2ddl.SchemaValidator;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
@ -128,6 +103,31 @@ import org.hibernate.type.TypeResolver;
import org.hibernate.util.CollectionHelper;
import org.hibernate.util.EmptyIterator;
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
* @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 IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator();
@ -178,7 +179,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
private final transient Settings settings;
private final transient Properties properties;
private transient SchemaExport schemaExport;
private final transient TransactionManager transactionManager;
private final transient QueryCache queryCache;
private final transient UpdateTimestampsCache updateTimestampsCache;
private final transient Map<String,QueryCache> queryCaches;
@ -195,6 +195,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
private transient boolean isClosed = false;
private final transient TypeResolver typeResolver;
private final transient TypeHelper typeHelper;
private final transient TransactionEnvironment transactionEnvironment;
public SessionFactoryImpl(
Configuration cfg,
@ -386,17 +387,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
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();
if ( settings.isQueryCacheEnabled() ) {
@ -480,9 +470,14 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
fetchProfiles.put( fetchProfile.getName(), fetchProfile );
}
this.transactionEnvironment = new TransactionEnvironmentImpl( this );
this.observer.sessionFactoryCreated( this );
}
public TransactionEnvironment getTransactionEnvironment() {
return transactionEnvironment;
}
public Properties getProperties() {
return properties;
}
@ -728,14 +723,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
return interceptor;
}
public TransactionFactory getTransactionFactory() {
return settings.getTransactionFactory();
}
public TransactionManager getTransactionManager() {
return transactionManager;
}
public SQLExceptionConverter getSQLExceptionConverter() {
return getSQLExceptionHelper().getSqlExceptionConverter();
}
@ -1229,19 +1216,34 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
return (IdentifierGenerator) identifierGenerators.get(rootEntityName);
}
private CurrentSessionContext buildCurrentSessionContext() {
String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
// for backward-compatability
if ( impl == null && transactionManager != null ) {
impl = "jta";
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() {
String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
// for backward-compatibility
if ( impl == null ) {
if ( canAccessTransactionManager() ) {
impl = "jta";
}
else {
return null;
}
else if ( "jta".equals( impl ) ) {
if ( settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions() ) {
log.warn( "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
}
if ( "jta".equals( impl ) ) {
if ( ! transactionFactory().compatibleWithJtaSynchronization() ) {
log.warn( "JTASessionContext being used with JdbcTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
}
return new JTASessionContext( this );
}
@ -1256,7 +1258,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
Class implClass = ReflectHelper.classForName( impl );
return ( CurrentSessionContext ) implClass
.getConstructor( new Class[] { SessionFactoryImplementor.class } )
.newInstance( new Object[] { this } );
.newInstance( this );
}
catch( Throwable 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;
}
@Override
public ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
public EntityNotFoundDelegate getEntityNotFoundDelegate() {
return entityNotFoundDelegate;
}

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,44 +20,21 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
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.ConnectionReleaseMode;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.LobHelper;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.Query;
@ -68,33 +45,34 @@ import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionException;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.TransientObjectException;
import org.hibernate.TypeHelper;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.UnknownProfileException;
import org.hibernate.EntityNameResolver;
import org.hibernate.LockOptions;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.ActionQueue;
import org.hibernate.engine.CollectionEntry;
import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.NonFlushedChanges;
import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.StatefulPersistenceContext;
import org.hibernate.engine.Status;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.jdbc.LobCreationContext;
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.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan;
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.AutoFlushEventListener;
import org.hibernate.event.DeleteEvent;
@ -136,57 +114,84 @@ import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.stat.SessionStatistics;
import org.hibernate.stat.SessionStatisticsImpl;
import org.hibernate.type.Type;
import org.hibernate.type.SerializationException;
import org.hibernate.type.Type;
import org.hibernate.util.ArrayHelper;
import org.hibernate.util.CollectionHelper;
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
* of Hibernate's internal implementation. As such, this class exposes two interfaces;
* Session itself, to the application, and SessionImplementor, to other components
* of Hibernate. This class is not threadsafe.
* Concrete implementation of a Session.
*
* Exposes two interfaces:<ul>
* <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
*/
public final class SessionImpl extends AbstractSessionImpl
implements EventSource, org.hibernate.classic.Session, JDBCContext.Context, LobCreationContext {
public final class SessionImpl
extends AbstractSessionImpl
implements EventSource,
org.hibernate.classic.Session,
TransactionContext,
LobCreationContext {
// 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...
// passing around seperate reto interceptor, factory, actionQueue, and persistentContext is not manageable...
// a separate class responsible for generating/dispatching events just duplicates most of the Session methods...
// passing around separate interceptor, factory, actionQueue, and persistentContext is not manageable...
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 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 StatefulPersistenceContext persistenceContext;
private transient JDBCContextImpl jdbcContext;
private transient TransactionCoordinatorImpl transactionCoordinator;
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 autoCloseSessionEnabled;
private transient ConnectionReleaseMode connectionReleaseMode;
private transient LoadQueryInfluencers loadQueryInfluencers;
private transient Session rootSession;
private transient Map childSessionsByEntityMode;
private transient EntityNameResolver entityNameResolver = new CoordinatingEntityNameResolver();
/**
* Constructor used in building "child sessions".
*
@ -197,7 +202,7 @@ public final class SessionImpl extends AbstractSessionImpl
super( parent.factory );
this.rootSession = parent;
this.timestamp = parent.timestamp;
this.jdbcContext = parent.jdbcContext;
this.transactionCoordinator = parent.transactionCoordinator;
this.interceptor = parent.interceptor;
this.listeners = parent.listeners;
this.actionQueue = new ActionQueue( this );
@ -251,7 +256,11 @@ public final class SessionImpl extends AbstractSessionImpl
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
this.autoCloseSessionEnabled = autoCloseSessionEnabled;
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 );
@ -330,7 +339,7 @@ public final class SessionImpl extends AbstractSessionImpl
}
if ( rootSession == null ) {
return jdbcContext.getConnectionManager().close();
return transactionCoordinator.close();
}
else {
return null;
@ -343,7 +352,6 @@ public final class SessionImpl extends AbstractSessionImpl
}
public ConnectionReleaseMode getConnectionReleaseMode() {
checkTransactionSynchStatus();
return connectionReleaseMode;
}
@ -523,50 +531,37 @@ public final class SessionImpl extends AbstractSessionImpl
public Connection connection() throws HibernateException {
errorIfClosed();
return jdbcContext.borrowConnection();
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getDistinctConnectionProxy();
}
public boolean isConnected() {
checkTransactionSynchStatus();
return !isClosed() && jdbcContext.getConnectionManager().isCurrentlyConnected();
return !isClosed() && transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isOpen();
}
public boolean isTransactionInProgress() {
checkTransactionSynchStatus();
return !isClosed() && jdbcContext.isTransactionInProgress();
return !isClosed() && transactionCoordinator.isTransactionInProgress();
}
public Connection disconnect() throws HibernateException {
errorIfClosed();
log.debug( "disconnecting session" );
return jdbcContext.getConnectionManager().manualDisconnect();
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualDisconnect();
}
public void reconnect() throws HibernateException {
errorIfClosed();
log.debug( "reconnecting session" );
checkTransactionSynchStatus();
jdbcContext.getConnectionManager().manualReconnect();
transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualReconnect( null );
}
public void reconnect(Connection conn) throws HibernateException {
errorIfClosed();
log.debug( "reconnecting session" );
checkTransactionSynchStatus();
jdbcContext.getConnectionManager().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);
}
}
transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualReconnect( conn );
}
public void setAutoClear(boolean enabled) {
@ -581,18 +576,39 @@ public final class SessionImpl extends AbstractSessionImpl
* completion processing
*/
public void afterOperation(boolean success) {
if ( !jdbcContext.isTransactionInProgress() ) {
jdbcContext.afterNontransactionalQuery( success );
if ( ! transactionCoordinator.isTransactionInProgress() ) {
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" );
persistenceContext.afterTransactionCompletion();
actionQueue.afterTransactionCompletion(success);
if ( rootSession == null && tx != null ) {
actionQueue.afterTransactionCompletion( successful );
if ( rootSession == null && hibernateTransaction != null ) {
try {
interceptor.afterTransactionCompletion(tx);
interceptor.afterTransactionCompletion( hibernateTransaction );
}
catch (Throwable t) {
log.error("exception in interceptor afterTransactionCompletion()", t);
@ -1449,7 +1465,7 @@ public final class SessionImpl extends AbstractSessionImpl
public Transaction getTransaction() throws HibernateException {
errorIfClosed();
return jdbcContext.getTransaction();
return transactionCoordinator.getTransaction();
}
public Transaction beginTransaction() throws HibernateException {
@ -1464,11 +1480,6 @@ public final class SessionImpl extends AbstractSessionImpl
return result;
}
public void afterTransactionBegin(Transaction tx) {
errorIfClosed();
interceptor.afterTransactionBegin(tx);
}
public EntityPersister getEntityPersister(final String entityName, final Object object) {
errorIfClosed();
if (entityName==null) {
@ -1839,7 +1850,7 @@ public final class SessionImpl extends AbstractSessionImpl
}
}
public SessionFactory getSessionFactory() {
public SessionFactoryImplementor getSessionFactory() {
checkTransactionSynchStatus();
return factory;
}
@ -1858,7 +1869,7 @@ public final class SessionImpl extends AbstractSessionImpl
if (object instanceof HibernateProxy) {
LazyInitializer initializer = ( ( HibernateProxy ) object ).getHibernateLazyInitializer();
// 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() ) {
return initializer.getEntityName();
}
@ -1904,7 +1915,7 @@ public final class SessionImpl extends AbstractSessionImpl
public void cancelQuery() throws HibernateException {
errorIfClosed();
getJDBCContext().getConnectionManager().cancelLastQuery();
getTransactionCoordinator().getJdbcCoordinator().cancelLastQuery();
}
public Interceptor getInterceptor() {
@ -1983,23 +1994,17 @@ public final class SessionImpl extends AbstractSessionImpl
}
public void doWork(Work work) throws HibernateException {
try {
work.execute( jdbcContext.getConnectionManager().getConnection() );
jdbcContext.getConnectionManager().afterStatement();
}
catch ( SQLException e ) {
throw factory.getSQLExceptionHelper().convert( e, "error executing work" );
}
transactionCoordinator.getJdbcCoordinator().coordinateWork( work );
}
public void afterScrollOperation() {
// nothing to do in a stateful session
}
public JDBCContext getJDBCContext() {
@Override
public TransactionCoordinator getTransactionCoordinator() {
errorIfClosed();
checkTransactionSynchStatus();
return jdbcContext;
return transactionCoordinator;
}
public LoadQueryInfluencers getLoadQueryInfluencers() {
@ -2098,8 +2103,8 @@ public final class SessionImpl extends AbstractSessionImpl
private void checkTransactionSynchStatus() {
if ( jdbcContext != null && !isClosed() ) {
jdbcContext.registerSynchronizationIfPossible();
if ( !isClosed() ) {
transactionCoordinator.pulse();
}
}
@ -2131,7 +2136,7 @@ public final class SessionImpl extends AbstractSessionImpl
listeners = factory.getEventListeners();
if ( isRootSession ) {
jdbcContext = JDBCContextImpl.deserialize( ois, this, interceptor );
transactionCoordinator = TransactionCoordinatorImpl.deserialize( ois, this );
}
persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
@ -2156,7 +2161,7 @@ public final class SessionImpl extends AbstractSessionImpl
while ( iter.hasNext() ) {
final SessionImpl child = ( ( SessionImpl ) iter.next() );
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
*/
private void writeObject(ObjectOutputStream oos) throws IOException {
if ( !jdbcContext.isReadyForSerialization() ) {
if ( ! transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isReadyForSerialization() ) {
throw new IllegalStateException( "Cannot serialize a session while connected" );
}
@ -2190,7 +2195,7 @@ public final class SessionImpl extends AbstractSessionImpl
factory.serialize( oos );
if ( rootSession == null ) {
jdbcContext.serialize( oos );
transactionCoordinator.serialize( oos );
}
persistenceContext.serialize( oos );
@ -2204,8 +2209,8 @@ public final class SessionImpl extends AbstractSessionImpl
/**
* {@inheritDoc}
*/
public Object execute(Callback callback) {
Connection connection = jdbcContext.getConnectionManager().getConnection();
public Object execute(LobCreationContext.Callback callback) {
Connection connection = transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getConnection();
try {
return callback.executeOnConnection( connection );
}
@ -2216,7 +2221,7 @@ public final class SessionImpl extends AbstractSessionImpl
);
}
finally {
jdbcContext.getConnectionManager().afterStatement();
transactionCoordinator.getJdbcCoordinator().getLogicalConnection().afterStatementExecution();
}
}

View File

@ -21,16 +21,6 @@
*/
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.ConnectionReleaseMode;
import org.hibernate.Criteria;
@ -50,17 +40,19 @@ import org.hibernate.UnresolvableObjectException;
import org.hibernate.cache.CacheKey;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.NonFlushedChanges;
import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.StatefulPersistenceContext;
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.NativeSQLQueryPlan;
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.id.IdentifierGeneratorHelper;
import org.hibernate.loader.criteria.CriteriaLoader;
@ -72,23 +64,42 @@ import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.type.Type;
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
*/
public class StatelessSessionImpl extends AbstractSessionImpl
implements JDBCContext.Context, StatelessSession {
public class StatelessSessionImpl extends AbstractSessionImpl implements StatelessSession {
private static final Logger log = LoggerFactory.getLogger( StatelessSessionImpl.class );
private JDBCContextImpl jdbcContext;
private TransactionCoordinator transactionCoordinator;
private PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this );
StatelessSessionImpl(Connection connection, SessionFactoryImpl 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -324,22 +335,33 @@ public class StatelessSessionImpl extends AbstractSessionImpl
if ( isClosed() ) {
throw new SessionException( "Session was already closed!" );
}
jdbcContext.getConnectionManager().close();
transactionCoordinator.close();
setClosed();
}
public void managedFlush() {
errorIfClosed();
getJDBCContext().getConnectionManager().executeBatch();
getTransactionCoordinator().getJdbcCoordinator().executeBatch();
}
public boolean shouldAutoClose() {
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) {
if (object instanceof HibernateProxy) {
@ -350,7 +372,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public Connection connection() {
errorIfClosed();
return jdbcContext.borrowConnection();
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getDistinctConnectionProxy();
}
public int executeUpdate(String query, QueryParameters queryParameters)
@ -444,11 +466,11 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public boolean isConnected() {
return jdbcContext.getConnectionManager().isCurrentlyConnected();
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected();
}
public boolean isTransactionInProgress() {
return jdbcContext.isTransactionInProgress();
return transactionCoordinator.isTransactionInProgress();
}
public void setAutoClear(boolean enabled) {
@ -465,7 +487,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public Transaction getTransaction() throws HibernateException {
errorIfClosed();
return jdbcContext.getTransaction();
return transactionCoordinator.getTransaction();
}
public Transaction beginTransaction() throws HibernateException {
@ -517,8 +539,8 @@ public class StatelessSessionImpl extends AbstractSessionImpl
}
public void afterOperation(boolean success) {
if ( !jdbcContext.isTransactionInProgress() ) {
jdbcContext.afterNontransactionalQuery(success);
if ( ! transactionCoordinator.isTransactionInProgress() ) {
transactionCoordinator.afterNonTransactionalQuery( success );;
}
}
@ -646,10 +668,6 @@ public class StatelessSessionImpl extends AbstractSessionImpl
return null;
}
public JDBCContext getJDBCContext() {
return jdbcContext;
}
public LoadQueryInfluencers getLoadQueryInfluencers() {
return LoadQueryInfluencers.NONE;
}
@ -667,8 +685,6 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public void setFetchProfile(String name) {}
public void afterTransactionBegin(Transaction tx) {}
protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
// no auto-flushing to support in stateless session
return false;

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