Merge branch 'master' of github.com:hibernate/hibernate-core
This commit is contained in:
commit
1dc88b3c38
|
@ -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
|
||||
}
|
||||
|
|
|
@ -97,3 +97,8 @@ task installTesting(type:Upload, dependsOn: [testingJar,testingSourcesJar]) {
|
|||
|
||||
install.dependsOn installTesting
|
||||
uploadTesting.dependsOn installTesting
|
||||
|
||||
// temporary
|
||||
test {
|
||||
ignoreFailures = true
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,4 +47,9 @@ public interface ConnectionObserver {
|
|||
* The logical connection was closed.
|
||||
*/
|
||||
public void logicalConnectionClosed();
|
||||
|
||||
/**
|
||||
* Notification of a statement being prepared
|
||||
*/
|
||||
public void statementPrepared();
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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";
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
*/
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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" );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
}
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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++ ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue