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',
|
jcl: 'commons-logging:commons-logging:99.0-does-not-exist',
|
||||||
|
|
||||||
// testing
|
// testing
|
||||||
|
atomikos: 'com.atomikos:transactions-jdbc:3.7.0',
|
||||||
junit: 'junit:junit:3.8.2',
|
junit: 'junit:junit:3.8.2',
|
||||||
testng: 'org.testng:testng:5.8:jdk15',
|
testng: 'org.testng:testng:5.8:jdk15',
|
||||||
jpa_modelgen: 'org.hibernate:hibernate-jpamodelgen:1.1.0.Final',
|
jpa_modelgen: 'org.hibernate:hibernate-jpamodelgen:1.1.0.Final',
|
||||||
|
@ -106,6 +107,7 @@ subprojects { subProject ->
|
||||||
dependencies {
|
dependencies {
|
||||||
compile( libraries.slf4j_api )
|
compile( libraries.slf4j_api )
|
||||||
testCompile( libraries.junit )
|
testCompile( libraries.junit )
|
||||||
|
testCompile( libraries.atomikos )
|
||||||
testRuntime( libraries.slf4j_simple )
|
testRuntime( libraries.slf4j_simple )
|
||||||
testRuntime( libraries.jcl_slf4j )
|
testRuntime( libraries.jcl_slf4j )
|
||||||
testRuntime( libraries.jcl_api )
|
testRuntime( libraries.jcl_api )
|
||||||
|
@ -151,12 +153,8 @@ subprojects { subProject ->
|
||||||
sourceCompatibility = "1.6"
|
sourceCompatibility = "1.6"
|
||||||
|
|
||||||
ideaModule {
|
ideaModule {
|
||||||
// treat our "provided" configuration dependencies as "Compile" scope dependencies in IntelliJ
|
// treat our "provided" configuration dependencies as "compile" scope dependencies in IntelliJ
|
||||||
scopes.COMPILE.plus.add( configurations.provided )
|
scopes.COMPILE.plus.add( configurations.provided )
|
||||||
// Use explicitly separate compilation output directories for Gradle and IntelliJ
|
|
||||||
File baseDirectory = new File( subProject.buildDir, "idea/classes" )
|
|
||||||
outputDir = new File( baseDirectory, "main" )
|
|
||||||
testOutputDir = new File( baseDirectory, "test" )
|
|
||||||
whenConfigured { module ->
|
whenConfigured { module ->
|
||||||
module.dependencies*.exported = true
|
module.dependencies*.exported = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,4 +96,9 @@ task installTesting(type:Upload, dependsOn: [testingJar,testingSourcesJar]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
install.dependsOn installTesting
|
install.dependsOn installTesting
|
||||||
uploadTesting.dependsOn installTesting
|
uploadTesting.dependsOn installTesting
|
||||||
|
|
||||||
|
// temporary
|
||||||
|
test {
|
||||||
|
ignoreFailures = true
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,7 +20,6 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate;
|
package org.hibernate;
|
||||||
|
|
||||||
|
@ -35,6 +34,9 @@ package org.hibernate;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class HibernateException extends RuntimeException {
|
public class HibernateException extends RuntimeException {
|
||||||
|
public HibernateException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
public HibernateException(Throwable root) {
|
public HibernateException(Throwable root) {
|
||||||
super(root);
|
super(root);
|
||||||
|
@ -43,10 +45,6 @@ public class HibernateException extends RuntimeException {
|
||||||
public HibernateException(String string, Throwable root) {
|
public HibernateException(String string, Throwable root) {
|
||||||
super(string, root);
|
super(string, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HibernateException(String s) {
|
|
||||||
super(s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,22 +20,20 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction;
|
package org.hibernate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link TransactionManagerLookup} strategy for JRun4 AS
|
* Indicates an attempt was made to use a closed resource (Session, SessionFactory, etc).
|
||||||
*
|
*
|
||||||
* @author Joseph Bissen
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class JRun4TransactionManagerLookup extends JNDITransactionManagerLookup {
|
public class ResourceClosedException extends HibernateException {
|
||||||
|
public ResourceClosedException(String s) {
|
||||||
protected String getName() {
|
super( s );
|
||||||
return "java:/TransactionManager";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUserTransactionName() {
|
public ResourceClosedException(String string, Throwable root) {
|
||||||
return "java:comp/UserTransaction";
|
super( string, root );
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -119,8 +119,7 @@ public interface SessionFactory extends Referenceable, Serializable {
|
||||||
* for use.
|
* for use.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note that for backwards compatibility, if a {@link org.hibernate.context.CurrentSessionContext}
|
* Note that for backwards compatibility, if a {@link org.hibernate.context.CurrentSessionContext}
|
||||||
* is not configured but a JTA {@link org.hibernate.transaction.TransactionManagerLookup}
|
* is not configured but JTA is configured this will default to the {@link org.hibernate.context.JTASessionContext}
|
||||||
* is configured this will default to the {@link org.hibernate.context.JTASessionContext}
|
|
||||||
* impl.
|
* impl.
|
||||||
*
|
*
|
||||||
* @return The current session.
|
* @return The current session.
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,109 +20,140 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate;
|
package org.hibernate;
|
||||||
|
|
||||||
|
import org.hibernate.engine.transaction.spi.LocalStatus;
|
||||||
|
|
||||||
import javax.transaction.Synchronization;
|
import javax.transaction.Synchronization;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows the application to define units of work, while
|
* Defines the contract for abstracting applications from the configured underlying means of transaction management.
|
||||||
* maintaining abstraction from the underlying transaction
|
* Allows the application to define units of work, while maintaining abstraction from the underlying transaction
|
||||||
* implementation (eg. JTA, JDBC).<br>
|
* implementation (eg. JTA, JDBC).
|
||||||
* <br>
|
* <p/>
|
||||||
* A transaction is associated with a <tt>Session</tt> and is
|
* A transaction is associated with a {@link Session} and is usually initiated by a call to
|
||||||
* usually instantiated by a call to <tt>Session.beginTransaction()</tt>.
|
* {@link org.hibernate.Session#beginTransaction()}. A single session might span multiple transactions since
|
||||||
* A single session might span multiple transactions since
|
* the notion of a session (a conversation between the application and the datastore) is of coarser granularity than
|
||||||
* the notion of a session (a conversation between the application
|
* the notion of a transaction. However, it is intended that there be at most one uncommitted transaction associated
|
||||||
* and the datastore) is of coarser granularity than the notion of
|
* with a particular {@link Session} at any time.
|
||||||
* a transaction. However, it is intended that there be at most one
|
* <p/>
|
||||||
* uncommitted <tt>Transaction</tt> associated with a particular
|
* Implementers are not intended to be thread-safe.
|
||||||
* <tt>Session</tt> at any time.<br>
|
|
||||||
* <br>
|
|
||||||
* Implementors are not intended to be threadsafe.
|
|
||||||
*
|
*
|
||||||
* @see Session#beginTransaction()
|
|
||||||
* @see org.hibernate.transaction.TransactionFactory
|
|
||||||
* @author Anton van Straaten
|
* @author Anton van Straaten
|
||||||
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface Transaction {
|
public interface Transaction {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begin a new transaction.
|
* Is this transaction the initiator of any underlying transaction?
|
||||||
|
*
|
||||||
|
* @return {@literal true} if this transaction initiated the underlying transaction; {@literal false} otherwise.
|
||||||
*/
|
*/
|
||||||
public void begin() throws HibernateException;
|
public boolean isInitiator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush the associated <tt>Session</tt> and end the unit of work (unless
|
* Begin this transaction. No-op if the transaction has already been begun. Note that this is not necessarily
|
||||||
* we are in {@link FlushMode#MANUAL}.
|
* symmetrical since usually multiple calls to {@link #commit} or {@link #rollback} will error.
|
||||||
* </p>
|
|
||||||
* This method will commit the underlying transaction if and only
|
|
||||||
* if the underlying transaction was initiated by this object.
|
|
||||||
*
|
*
|
||||||
* @throws HibernateException
|
* @throws HibernateException Indicates a problem beginning the transaction.
|
||||||
*/
|
*/
|
||||||
public void commit() throws HibernateException;
|
public void begin();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force the underlying transaction to roll back.
|
* Commit this transaction. This might entail a number of things depending on the context:<ul>
|
||||||
|
* <li>
|
||||||
|
* If this transaction is the {@link #isInitiator initiator}, {@link Session#flush} the {@link Session}
|
||||||
|
* with which it is associated (unless {@link Session} is in {@link FlushMode#MANUAL}).
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* If this transaction is the {@link #isInitiator initiator}, commit the underlying transaction.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Coordinate various callbacks
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @throws HibernateException
|
* @throws HibernateException Indicates a problem committing the transaction.
|
||||||
*/
|
*/
|
||||||
public void rollback() throws HibernateException;
|
public void commit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollback this transaction. Either rolls back the underlying transaction or ensures it cannot later commit
|
||||||
|
* (depending on the actual underlying strategy).
|
||||||
|
*
|
||||||
|
* @throws HibernateException Indicates a problem rolling back the transaction.
|
||||||
|
*/
|
||||||
|
public void rollback();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current local status of this transaction.
|
||||||
|
* <p/>
|
||||||
|
* This only accounts for the local view of the transaction status. In other words it does not check the status
|
||||||
|
* of the actual underlying transaction.
|
||||||
|
*
|
||||||
|
* @return The current local status.
|
||||||
|
*/
|
||||||
|
public LocalStatus getLocalStatus();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this transaction still active?
|
||||||
|
* <p/>
|
||||||
|
* Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a
|
||||||
|
* transaction is active when it is initiated directly through the JDBC {@link java.sql.Connection}, only when
|
||||||
|
* it is initiated from here.
|
||||||
|
*
|
||||||
|
* @return {@literal true} if the transaction is still active; {@literal false} otherwise.
|
||||||
|
*
|
||||||
|
* @throws HibernateException Indicates a problem checking the transaction status.
|
||||||
|
*/
|
||||||
|
public boolean isActive();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was this transaction committed?
|
||||||
|
* <p/>
|
||||||
|
* Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a
|
||||||
|
* transaction was committed when the commit was performed directly through the JDBC {@link java.sql.Connection},
|
||||||
|
* only when the commit was done from this.
|
||||||
|
*
|
||||||
|
* @return {@literal true} if the transaction is rolled back; {@literal false} otherwise.
|
||||||
|
*
|
||||||
|
* @throws HibernateException Indicates a problem checking the transaction status.
|
||||||
|
*/
|
||||||
|
public boolean wasCommitted();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Was this transaction rolled back or set to rollback only?
|
* Was this transaction rolled back or set to rollback only?
|
||||||
* <p/>
|
* <p/>
|
||||||
* This only accounts for actions initiated from this local transaction.
|
* Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a
|
||||||
* If, for example, the underlying transaction is forced to rollback via
|
* transaction was rolled back when rollback was performed directly through the JDBC {@link java.sql.Connection},
|
||||||
* some other means, this method still reports false because the rollback
|
* only when it was rolled back from here.
|
||||||
* was not initiated from here.
|
|
||||||
*
|
*
|
||||||
* @return boolean True if the transaction was rolled back via this
|
* @return {@literal true} if the transaction is rolled back; {@literal false} otherwise.
|
||||||
* local transaction; false otherwise.
|
|
||||||
* @throws HibernateException
|
|
||||||
*/
|
|
||||||
public boolean wasRolledBack() throws HibernateException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if this transaction was successfully committed.
|
|
||||||
* <p/>
|
|
||||||
* This method could return <tt>false</tt> even after successful invocation
|
|
||||||
* of {@link #commit}. As an example, JTA based strategies no-op on
|
|
||||||
* {@link #commit} calls if they did not start the transaction; in that case,
|
|
||||||
* they also report {@link #wasCommitted} as false.
|
|
||||||
*
|
*
|
||||||
* @return boolean True if the transaction was (unequivocally) committed
|
* @throws HibernateException Indicates a problem checking the transaction status.
|
||||||
* via this local transaction; false otherwise.
|
|
||||||
* @throws HibernateException
|
|
||||||
*/
|
*/
|
||||||
public boolean wasCommitted() throws HibernateException;
|
public boolean wasRolledBack();
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this transaction still active?
|
|
||||||
* <p/>
|
|
||||||
* Again, this only returns information in relation to the
|
|
||||||
* local transaction, not the actual underlying transaction.
|
|
||||||
*
|
|
||||||
* @return boolean Treu if this local transaction is still active.
|
|
||||||
*/
|
|
||||||
public boolean isActive() throws HibernateException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a user synchronization callback for this transaction.
|
* Register a user synchronization callback for this transaction.
|
||||||
*
|
*
|
||||||
* @param synchronization The Synchronization callback to register.
|
* @param synchronization The Synchronization callback to register.
|
||||||
* @throws HibernateException
|
*
|
||||||
|
* @throws HibernateException Indicates a problem registering the synchronization.
|
||||||
*/
|
*/
|
||||||
public void registerSynchronization(Synchronization synchronization)
|
public void registerSynchronization(Synchronization synchronization) throws HibernateException;
|
||||||
throws HibernateException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the transaction timeout for any transaction started by
|
* Set the transaction timeout for any transaction started by a subsequent call to {@link #begin} on this instance.
|
||||||
* a subsequent call to <tt>begin()</tt> on this instance.
|
|
||||||
*
|
*
|
||||||
* @param seconds The number of seconds before a timeout.
|
* @param seconds The number of seconds before a timeout.
|
||||||
*/
|
*/
|
||||||
public void setTimeout(int seconds);
|
public void setTimeout(int seconds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the transaction timeout set for this transaction. A negative indicates no timeout has been set.
|
||||||
|
*
|
||||||
|
* @return The timeout, in seconds.
|
||||||
|
*/
|
||||||
|
public int getTimeout();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1842,7 +1842,7 @@ public class Configuration implements Serializable {
|
||||||
Properties copy = new Properties();
|
Properties copy = new Properties();
|
||||||
copy.putAll( properties );
|
copy.putAll( properties );
|
||||||
ConfigurationHelper.resolvePlaceHolders( copy );
|
ConfigurationHelper.resolvePlaceHolders( copy );
|
||||||
Settings settings = buildSettings( copy, serviceRegistry.getService( JdbcServices.class ) );
|
Settings settings = buildSettings( copy, serviceRegistry );
|
||||||
|
|
||||||
return new SessionFactoryImpl(
|
return new SessionFactoryImpl(
|
||||||
this,
|
this,
|
||||||
|
@ -2825,18 +2825,18 @@ public class Configuration implements Serializable {
|
||||||
*
|
*
|
||||||
* @return The build settings
|
* @return The build settings
|
||||||
*/
|
*/
|
||||||
public Settings buildSettings(JdbcServices jdbcServices) {
|
public Settings buildSettings(ServiceRegistry serviceRegistry) {
|
||||||
Properties clone = ( Properties ) properties.clone();
|
Properties clone = ( Properties ) properties.clone();
|
||||||
ConfigurationHelper.resolvePlaceHolders( clone );
|
ConfigurationHelper.resolvePlaceHolders( clone );
|
||||||
return buildSettingsInternal( clone, jdbcServices );
|
return buildSettingsInternal( clone, serviceRegistry );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings buildSettings(Properties props, JdbcServices jdbcServices) throws HibernateException {
|
public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException {
|
||||||
return buildSettingsInternal( props, jdbcServices );
|
return buildSettingsInternal( props, serviceRegistry );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Settings buildSettingsInternal(Properties props, JdbcServices jdbcServices) {
|
private Settings buildSettingsInternal(Properties props, ServiceRegistry serviceRegistry) {
|
||||||
final Settings settings = settingsFactory.buildSettings( props, jdbcServices );
|
final Settings settings = settingsFactory.buildSettings( props, serviceRegistry );
|
||||||
settings.setEntityTuplizerFactory( this.getEntityTuplizerFactory() );
|
settings.setEntityTuplizerFactory( this.getEntityTuplizerFactory() );
|
||||||
// settings.setComponentTuplizerFactory( this.getComponentTuplizerFactory() );
|
// settings.setComponentTuplizerFactory( this.getComponentTuplizerFactory() );
|
||||||
return settings;
|
return settings;
|
||||||
|
|
|
@ -164,7 +164,7 @@ import org.hibernate.util.ConfigHelper;
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td><tt>hibernate.transaction.factory_class</tt></td>
|
* <td><tt>hibernate.transaction.factory_class</tt></td>
|
||||||
* <td>the factory to use for instantiating <tt>Transaction</tt>s.
|
* <td>the factory to use for instantiating <tt>Transaction</tt>s.
|
||||||
* (Defaults to <tt>JDBCTransactionFactory</tt>.)</td>
|
* (Defaults to <tt>JdbcTransactionFactory</tt>.)</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td><tt>hibernate.query.substitutions</tt></td><td>query language token substitutions</td>
|
* <td><tt>hibernate.query.substitutions</tt></td><td>query language token substitutions</td>
|
||||||
|
@ -376,7 +376,8 @@ public final class Environment {
|
||||||
*/
|
*/
|
||||||
public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class";
|
public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class";
|
||||||
/**
|
/**
|
||||||
* <tt>TransactionFactory</tt> implementor to use for creating <tt>Transaction</tt>s
|
* Names the implementation of {@link org.hibernate.engine.transaction.spi.TransactionContext} to use for
|
||||||
|
* creating {@link org.hibernate.Transaction} instances
|
||||||
*/
|
*/
|
||||||
public static final String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class";
|
public static final String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class";
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,20 +23,18 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.cfg;
|
package org.hibernate.cfg;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
import org.hibernate.EntityMode;
|
import org.hibernate.EntityMode;
|
||||||
import org.hibernate.cache.QueryCacheFactory;
|
import org.hibernate.cache.QueryCacheFactory;
|
||||||
import org.hibernate.cache.RegionFactory;
|
import org.hibernate.cache.RegionFactory;
|
||||||
import org.hibernate.engine.jdbc.JdbcSupport;
|
import org.hibernate.engine.jdbc.JdbcSupport;
|
||||||
import org.hibernate.engine.jdbc.batch.internal.BatchBuilder;
|
|
||||||
import org.hibernate.hql.QueryTranslatorFactory;
|
import org.hibernate.hql.QueryTranslatorFactory;
|
||||||
import org.hibernate.jdbc.util.SQLStatementLogger;
|
import org.hibernate.jdbc.util.SQLStatementLogger;
|
||||||
import org.hibernate.transaction.TransactionFactory;
|
import org.hibernate.service.jta.platform.spi.JtaPlatform;
|
||||||
import org.hibernate.transaction.TransactionManagerLookup;
|
|
||||||
import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings that affect the behaviour of Hibernate at runtime.
|
* Settings that affect the behaviour of Hibernate at runtime.
|
||||||
*
|
*
|
||||||
|
@ -75,9 +73,6 @@ public final class Settings {
|
||||||
private ConnectionReleaseMode connectionReleaseMode;
|
private ConnectionReleaseMode connectionReleaseMode;
|
||||||
private RegionFactory regionFactory;
|
private RegionFactory regionFactory;
|
||||||
private QueryCacheFactory queryCacheFactory;
|
private QueryCacheFactory queryCacheFactory;
|
||||||
private TransactionFactory transactionFactory;
|
|
||||||
private TransactionManagerLookup transactionManagerLookup;
|
|
||||||
private BatchBuilder batchBuilder;
|
|
||||||
private QueryTranslatorFactory queryTranslatorFactory;
|
private QueryTranslatorFactory queryTranslatorFactory;
|
||||||
private boolean wrapResultSetsEnabled;
|
private boolean wrapResultSetsEnabled;
|
||||||
private boolean orderUpdatesEnabled;
|
private boolean orderUpdatesEnabled;
|
||||||
|
@ -94,6 +89,8 @@ public final class Settings {
|
||||||
private JdbcSupport jdbcSupport;
|
private JdbcSupport jdbcSupport;
|
||||||
private String importFiles;
|
private String importFiles;
|
||||||
|
|
||||||
|
private JtaPlatform jtaPlatform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Package protected constructor
|
* Package protected constructor
|
||||||
*/
|
*/
|
||||||
|
@ -162,10 +159,6 @@ public final class Settings {
|
||||||
return jdbcFetchSize;
|
return jdbcFetchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransactionFactory getTransactionFactory() {
|
|
||||||
return transactionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSessionFactoryName() {
|
public String getSessionFactoryName() {
|
||||||
return sessionFactoryName;
|
return sessionFactoryName;
|
||||||
}
|
}
|
||||||
|
@ -190,10 +183,6 @@ public final class Settings {
|
||||||
return regionFactory;
|
return regionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransactionManagerLookup getTransactionManagerLookup() {
|
|
||||||
return transactionManagerLookup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isQueryCacheEnabled() {
|
public boolean isQueryCacheEnabled() {
|
||||||
return queryCacheEnabled;
|
return queryCacheEnabled;
|
||||||
}
|
}
|
||||||
|
@ -226,10 +215,6 @@ public final class Settings {
|
||||||
return flushBeforeCompletionEnabled;
|
return flushBeforeCompletionEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BatchBuilder getBatchBuilder() {
|
|
||||||
return batchBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAutoCloseSessionEnabled() {
|
public boolean isAutoCloseSessionEnabled() {
|
||||||
return autoCloseSessionEnabled;
|
return autoCloseSessionEnabled;
|
||||||
}
|
}
|
||||||
|
@ -349,10 +334,6 @@ public final class Settings {
|
||||||
jdbcFetchSize = integer;
|
jdbcFetchSize = integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTransactionFactory(TransactionFactory factory) {
|
|
||||||
transactionFactory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSessionFactoryName(String string) {
|
void setSessionFactoryName(String string) {
|
||||||
sessionFactoryName = string;
|
sessionFactoryName = string;
|
||||||
}
|
}
|
||||||
|
@ -377,10 +358,6 @@ public final class Settings {
|
||||||
this.regionFactory = regionFactory;
|
this.regionFactory = regionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTransactionManagerLookup(TransactionManagerLookup lookup) {
|
|
||||||
transactionManagerLookup = lookup;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setQueryCacheEnabled(boolean b) {
|
void setQueryCacheEnabled(boolean b) {
|
||||||
queryCacheEnabled = b;
|
queryCacheEnabled = b;
|
||||||
}
|
}
|
||||||
|
@ -413,10 +390,6 @@ public final class Settings {
|
||||||
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
|
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBatcherBuilder(BatchBuilder batchBuilder) {
|
|
||||||
this.batchBuilder = batchBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAutoCloseSessionEnabled(boolean autoCloseSessionEnabled) {
|
void setAutoCloseSessionEnabled(boolean autoCloseSessionEnabled) {
|
||||||
this.autoCloseSessionEnabled = autoCloseSessionEnabled;
|
this.autoCloseSessionEnabled = autoCloseSessionEnabled;
|
||||||
}
|
}
|
||||||
|
@ -496,4 +469,13 @@ public final class Settings {
|
||||||
// void setBytecodeProvider(BytecodeProvider bytecodeProvider) {
|
// void setBytecodeProvider(BytecodeProvider bytecodeProvider) {
|
||||||
// this.bytecodeProvider = bytecodeProvider;
|
// this.bytecodeProvider = bytecodeProvider;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
public JtaPlatform getJtaPlatform() {
|
||||||
|
return jtaPlatform;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setJtaPlatform(JtaPlatform jtaPlatform) {
|
||||||
|
this.jtaPlatform = jtaPlatform;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,16 +39,14 @@ import org.hibernate.cache.QueryCacheFactory;
|
||||||
import org.hibernate.cache.RegionFactory;
|
import org.hibernate.cache.RegionFactory;
|
||||||
import org.hibernate.cache.impl.NoCachingRegionFactory;
|
import org.hibernate.cache.impl.NoCachingRegionFactory;
|
||||||
import org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge;
|
import org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge;
|
||||||
import org.hibernate.engine.jdbc.batch.internal.BatchBuilder;
|
|
||||||
import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
|
import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionFactory;
|
||||||
import org.hibernate.hql.QueryTranslatorFactory;
|
import org.hibernate.hql.QueryTranslatorFactory;
|
||||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
import org.hibernate.jdbc.util.SQLStatementLogger;
|
import org.hibernate.jdbc.util.SQLStatementLogger;
|
||||||
import org.hibernate.transaction.TransactionFactory;
|
import org.hibernate.service.jta.platform.spi.JtaPlatform;
|
||||||
import org.hibernate.transaction.TransactionFactoryFactory;
|
import org.hibernate.service.spi.ServiceRegistry;
|
||||||
import org.hibernate.transaction.TransactionManagerLookup;
|
|
||||||
import org.hibernate.transaction.TransactionManagerLookupFactory;
|
|
||||||
import org.hibernate.util.ReflectHelper;
|
import org.hibernate.util.ReflectHelper;
|
||||||
import org.hibernate.util.StringHelper;
|
import org.hibernate.util.StringHelper;
|
||||||
|
|
||||||
|
@ -66,7 +64,8 @@ public class SettingsFactory implements Serializable {
|
||||||
protected SettingsFactory() {
|
protected SettingsFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings buildSettings(Properties props, JdbcServices jdbcServices) {
|
public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) {
|
||||||
|
final JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class );
|
||||||
Settings settings = new Settings();
|
Settings settings = new Settings();
|
||||||
|
|
||||||
//SessionFactory name:
|
//SessionFactory name:
|
||||||
|
@ -90,10 +89,7 @@ public class SettingsFactory implements Serializable {
|
||||||
settings.setJdbcSupport( new JdbcSupport( ! ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, properties ) ) );
|
settings.setJdbcSupport( new JdbcSupport( ! ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, properties ) ) );
|
||||||
|
|
||||||
// Transaction settings:
|
// Transaction settings:
|
||||||
|
settings.setJtaPlatform( serviceRegistry.getService( JtaPlatform.class ) );
|
||||||
TransactionFactory transactionFactory = createTransactionFactory(properties);
|
|
||||||
settings.setTransactionFactory(transactionFactory);
|
|
||||||
settings.setTransactionManagerLookup( createTransactionManagerLookup(properties) );
|
|
||||||
|
|
||||||
boolean flushBeforeCompletion = ConfigurationHelper.getBoolean(Environment.FLUSH_BEFORE_COMPLETION, properties);
|
boolean flushBeforeCompletion = ConfigurationHelper.getBoolean(Environment.FLUSH_BEFORE_COMPLETION, properties);
|
||||||
log.info("Automatic flush during beforeCompletion(): " + enabledDisabled(flushBeforeCompletion) );
|
log.info("Automatic flush during beforeCompletion(): " + enabledDisabled(flushBeforeCompletion) );
|
||||||
|
@ -112,7 +108,6 @@ public class SettingsFactory implements Serializable {
|
||||||
boolean jdbcBatchVersionedData = ConfigurationHelper.getBoolean(Environment.BATCH_VERSIONED_DATA, properties, false);
|
boolean jdbcBatchVersionedData = ConfigurationHelper.getBoolean(Environment.BATCH_VERSIONED_DATA, properties, false);
|
||||||
if (batchSize>0) log.info("JDBC batch updates for versioned data: " + enabledDisabled(jdbcBatchVersionedData) );
|
if (batchSize>0) log.info("JDBC batch updates for versioned data: " + enabledDisabled(jdbcBatchVersionedData) );
|
||||||
settings.setJdbcBatchVersionedData(jdbcBatchVersionedData);
|
settings.setJdbcBatchVersionedData(jdbcBatchVersionedData);
|
||||||
settings.setBatcherBuilder( createBatchBuilder(properties, batchSize) );
|
|
||||||
|
|
||||||
boolean useScrollableResultSets = ConfigurationHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, meta.supportsScrollableResults());
|
boolean useScrollableResultSets = ConfigurationHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, meta.supportsScrollableResults());
|
||||||
log.info("Scrollable result sets: " + enabledDisabled(useScrollableResultSets) );
|
log.info("Scrollable result sets: " + enabledDisabled(useScrollableResultSets) );
|
||||||
|
@ -134,7 +129,7 @@ public class SettingsFactory implements Serializable {
|
||||||
log.info( "Connection release mode: " + releaseModeName );
|
log.info( "Connection release mode: " + releaseModeName );
|
||||||
ConnectionReleaseMode releaseMode;
|
ConnectionReleaseMode releaseMode;
|
||||||
if ( "auto".equals(releaseModeName) ) {
|
if ( "auto".equals(releaseModeName) ) {
|
||||||
releaseMode = transactionFactory.getDefaultReleaseMode();
|
releaseMode = serviceRegistry.getService( TransactionFactory.class ).getDefaultReleaseMode();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
releaseMode = ConnectionReleaseMode.parse( releaseModeName );
|
releaseMode = ConnectionReleaseMode.parse( releaseModeName );
|
||||||
|
@ -301,7 +296,9 @@ public class SettingsFactory implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegionFactory createRegionFactory(Properties properties, boolean cachingEnabled) {
|
public static RegionFactory createRegionFactory(Properties properties, boolean cachingEnabled) {
|
||||||
String regionFactoryClassName = ConfigurationHelper.getString( Environment.CACHE_REGION_FACTORY, properties, null );
|
String regionFactoryClassName = ConfigurationHelper.getString(
|
||||||
|
Environment.CACHE_REGION_FACTORY, properties, null
|
||||||
|
);
|
||||||
if ( regionFactoryClassName == null && cachingEnabled ) {
|
if ( regionFactoryClassName == null && cachingEnabled ) {
|
||||||
String providerClassName = ConfigurationHelper.getString( Environment.CACHE_PROVIDER, properties, null );
|
String providerClassName = ConfigurationHelper.getString( Environment.CACHE_PROVIDER, properties, null );
|
||||||
if ( providerClassName != null ) {
|
if ( providerClassName != null ) {
|
||||||
|
@ -346,33 +343,4 @@ public class SettingsFactory implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BatchBuilder createBatchBuilder(Properties properties, int batchSize) {
|
|
||||||
String batchBuilderClass = properties.getProperty(Environment.BATCH_STRATEGY);
|
|
||||||
BatchBuilder batchBuilder;
|
|
||||||
if (batchBuilderClass==null) {
|
|
||||||
batchBuilder = batchSize > 0
|
|
||||||
? new BatchBuilder( batchSize )
|
|
||||||
: new BatchBuilder();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.info("Batch factory: " + batchBuilderClass);
|
|
||||||
try {
|
|
||||||
batchBuilder = (BatchBuilder) ReflectHelper.classForName(batchBuilderClass).newInstance();
|
|
||||||
}
|
|
||||||
catch (Exception cnfe) {
|
|
||||||
throw new HibernateException("could not instantiate BatchBuilder: " + batchBuilderClass, cnfe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
batchBuilder.setJdbcBatchSize( batchSize );
|
|
||||||
return batchBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TransactionFactory createTransactionFactory(Properties properties) {
|
|
||||||
return TransactionFactoryFactory.buildTransactionFactory(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TransactionManagerLookup createTransactionManagerLookup(Properties properties) {
|
|
||||||
return TransactionManagerLookupFactory.getTransactionManagerLookup(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,8 @@ import org.hibernate.HibernateException;
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
import org.hibernate.classic.Session;
|
import org.hibernate.classic.Session;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
import org.hibernate.util.JTAHelper;
|
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
|
||||||
|
import org.hibernate.service.jta.platform.spi.JtaPlatform;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -76,7 +77,8 @@ public class JTASessionContext implements CurrentSessionContext {
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public Session currentSession() throws HibernateException {
|
public Session currentSession() throws HibernateException {
|
||||||
TransactionManager transactionManager = factory.getTransactionManager();
|
final JtaPlatform jtaPlatform = factory.getServiceRegistry().getService( JtaPlatform.class );
|
||||||
|
final TransactionManager transactionManager = jtaPlatform.retrieveTransactionManager();
|
||||||
if ( transactionManager == null ) {
|
if ( transactionManager == null ) {
|
||||||
throw new HibernateException( "No TransactionManagerLookup specified" );
|
throw new HibernateException( "No TransactionManagerLookup specified" );
|
||||||
}
|
}
|
||||||
|
@ -87,9 +89,9 @@ public class JTASessionContext implements CurrentSessionContext {
|
||||||
if ( txn == null ) {
|
if ( txn == null ) {
|
||||||
throw new HibernateException( "Unable to locate current JTA transaction" );
|
throw new HibernateException( "Unable to locate current JTA transaction" );
|
||||||
}
|
}
|
||||||
if ( !JTAHelper.isInProgress( txn.getStatus() ) ) {
|
if ( !JtaStatusHelper.isActive( txn.getStatus() ) ) {
|
||||||
// We could register the session against the transaction even though it is
|
// We could register the session against the transaction even though it is
|
||||||
// not started, but we'd have no guarentee of ever getting the map
|
// not started, but we'd have no guarantee of ever getting the map
|
||||||
// entries cleaned up (aside from spawning threads).
|
// entries cleaned up (aside from spawning threads).
|
||||||
throw new HibernateException( "Current transaction is not in progress" );
|
throw new HibernateException( "Current transaction is not in progress" );
|
||||||
}
|
}
|
||||||
|
@ -101,9 +103,7 @@ public class JTASessionContext implements CurrentSessionContext {
|
||||||
throw new HibernateException( "Problem locating/validating JTA transaction", t );
|
throw new HibernateException( "Problem locating/validating JTA transaction", t );
|
||||||
}
|
}
|
||||||
|
|
||||||
final Object txnIdentifier = factory.getSettings().getTransactionManagerLookup() == null
|
final Object txnIdentifier = jtaPlatform.getTransactionIdentifier( txn );
|
||||||
? txn
|
|
||||||
: factory.getSettings().getTransactionManagerLookup().getTransactionIdentifier( txn );
|
|
||||||
|
|
||||||
Session currentSession = ( Session ) currentSessionMap.get( txnIdentifier );
|
Session currentSession = ( Session ) currentSessionMap.get( txnIdentifier );
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,10 @@ import org.hibernate.HibernateException;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.classic.Session;
|
import org.hibernate.classic.Session;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.engine.SessionImplementor;
|
||||||
|
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionContext;
|
||||||
|
import org.hibernate.event.EventSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link CurrentSessionContext} impl which scopes the notion of current
|
* A {@link CurrentSessionContext} impl which scopes the notion of current
|
||||||
|
@ -74,11 +78,11 @@ public class ThreadLocalSessionContext implements CurrentSessionContext {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger( ThreadLocalSessionContext.class );
|
private static final Logger log = LoggerFactory.getLogger( ThreadLocalSessionContext.class );
|
||||||
private static final Class[] SESSION_PROXY_INTERFACES = new Class[] {
|
private static final Class[] SESSION_PROXY_INTERFACES = new Class[] {
|
||||||
org.hibernate.classic.Session.class,
|
Session.class,
|
||||||
org.hibernate.engine.SessionImplementor.class,
|
SessionImplementor.class,
|
||||||
org.hibernate.engine.jdbc.spi.JDBCContext.Context.class,
|
EventSource.class,
|
||||||
org.hibernate.event.EventSource.class,
|
TransactionContext.class,
|
||||||
org.hibernate.engine.jdbc.LobCreationContext.class
|
LobCreationContext.class
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -78,7 +78,7 @@ public class PessimisticReadSelectLockingStrategy extends AbstractSelectLockingS
|
||||||
final String sql = determineSql( timeout );
|
final String sql = determineSql( timeout );
|
||||||
SessionFactoryImplementor factory = session.getFactory();
|
SessionFactoryImplementor factory = session.getFactory();
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
|
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
|
||||||
if ( getLockable().isVersioned() ) {
|
if ( getLockable().isVersioned() ) {
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class PessimisticReadUpdateLockingStrategy implements LockingStrategy {
|
||||||
}
|
}
|
||||||
SessionFactoryImplementor factory = session.getFactory();
|
SessionFactoryImplementor factory = session.getFactory();
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
lockable.getVersionType().nullSafeSet( st, version, 1, session );
|
lockable.getVersionType().nullSafeSet( st, version, 1, session );
|
||||||
int offset = 2;
|
int offset = 2;
|
||||||
|
|
|
@ -78,7 +78,7 @@ public class PessimisticWriteSelectLockingStrategy extends AbstractSelectLocking
|
||||||
final String sql = determineSql( timeout );
|
final String sql = determineSql( timeout );
|
||||||
SessionFactoryImplementor factory = session.getFactory();
|
SessionFactoryImplementor factory = session.getFactory();
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
|
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
|
||||||
if ( getLockable().isVersioned() ) {
|
if ( getLockable().isVersioned() ) {
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class PessimisticWriteUpdateLockingStrategy implements LockingStrategy {
|
||||||
}
|
}
|
||||||
SessionFactoryImplementor factory = session.getFactory();
|
SessionFactoryImplementor factory = session.getFactory();
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
lockable.getVersionType().nullSafeSet( st, version, 1, session );
|
lockable.getVersionType().nullSafeSet( st, version, 1, session );
|
||||||
int offset = 2;
|
int offset = 2;
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class SelectLockingStrategy extends AbstractSelectLockingStrategy {
|
||||||
final String sql = determineSql( timeout );
|
final String sql = determineSql( timeout );
|
||||||
SessionFactoryImplementor factory = session.getFactory();
|
SessionFactoryImplementor factory = session.getFactory();
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
|
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
|
||||||
if ( getLockable().isVersioned() ) {
|
if ( getLockable().isVersioned() ) {
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class UpdateLockingStrategy implements LockingStrategy {
|
||||||
// todo : should we additionally check the current isolation mode explicitly?
|
// todo : should we additionally check the current isolation mode explicitly?
|
||||||
SessionFactoryImplementor factory = session.getFactory();
|
SessionFactoryImplementor factory = session.getFactory();
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
lockable.getVersionType().nullSafeSet( st, version, 1, session );
|
lockable.getVersionType().nullSafeSet( st, version, 1, session );
|
||||||
int offset = 2;
|
int offset = 2;
|
||||||
|
|
|
@ -265,7 +265,7 @@ public class ActionQueue {
|
||||||
execute( ( Executable ) list.get( i ) );
|
execute( ( Executable ) list.get( i ) );
|
||||||
}
|
}
|
||||||
list.clear();
|
list.clear();
|
||||||
session.getJDBCContext().getConnectionManager().executeBatch();
|
session.getTransactionCoordinator().getJdbcCoordinator().executeBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void execute(Executable executable) {
|
public void execute(Executable executable) {
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.function.SQLFunctionRegistry;
|
import org.hibernate.dialect.function.SQLFunctionRegistry;
|
||||||
import org.hibernate.exception.SQLExceptionConverter;
|
import org.hibernate.exception.SQLExceptionConverter;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
|
import org.hibernate.service.spi.ServiceRegistry;
|
||||||
import org.hibernate.stat.StatisticsImplementor;
|
import org.hibernate.stat.StatisticsImplementor;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.type.TypeResolver;
|
import org.hibernate.type.TypeResolver;
|
||||||
|
@ -145,13 +146,6 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
|
||||||
*/
|
*/
|
||||||
public String getImportedClassName(String name);
|
public String getImportedClassName(String name);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the JTA transaction manager
|
|
||||||
*/
|
|
||||||
public TransactionManager getTransactionManager();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default query cache
|
* Get the default query cache
|
||||||
*/
|
*/
|
||||||
|
@ -262,4 +256,5 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
|
||||||
*/
|
*/
|
||||||
public FetchProfile getFetchProfile(String name);
|
public FetchProfile getFetchProfile(String name);
|
||||||
|
|
||||||
|
public ServiceRegistry getServiceRegistry();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,9 @@ import org.hibernate.Query;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
import org.hibernate.engine.jdbc.spi.JDBCContext;
|
|
||||||
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
||||||
import org.hibernate.collection.PersistentCollection;
|
import org.hibernate.collection.PersistentCollection;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||||
import org.hibernate.event.EventListeners;
|
import org.hibernate.event.EventListeners;
|
||||||
import org.hibernate.impl.CriteriaImpl;
|
import org.hibernate.impl.CriteriaImpl;
|
||||||
import org.hibernate.loader.custom.CustomQuery;
|
import org.hibernate.loader.custom.CustomQuery;
|
||||||
|
@ -157,20 +157,6 @@ public interface SessionImplementor extends Serializable {
|
||||||
*/
|
*/
|
||||||
public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException;
|
public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the session that the transaction completed, so we no longer
|
|
||||||
* own the old locks. (Also we should release cache softlocks.) May
|
|
||||||
* be called multiple times during the transaction completion process.
|
|
||||||
* Also called after an autocommit, in which case the second argument
|
|
||||||
* is null.
|
|
||||||
*/
|
|
||||||
public void afterTransactionCompletion(boolean successful, Transaction tx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the session that the transaction is about to complete
|
|
||||||
*/
|
|
||||||
public void beforeTransactionCompletion(Transaction tx);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the identifier of the persistent object, or null if
|
* Return the identifier of the persistent object, or null if
|
||||||
* not associated with the session
|
* not associated with the session
|
||||||
|
@ -340,11 +326,16 @@ public interface SessionImplementor extends Serializable {
|
||||||
*/
|
*/
|
||||||
public void setFetchProfile(String name);
|
public void setFetchProfile(String name);
|
||||||
|
|
||||||
public JDBCContext getJDBCContext();
|
/**
|
||||||
|
* Retrieve access to the session's transaction coordinator.
|
||||||
|
*
|
||||||
|
* @return The transaction coordinator.
|
||||||
|
*/
|
||||||
|
public TransactionCoordinator getTransactionCoordinator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the session is closed. Provided seperately from
|
* Determine whether the session is closed. Provided separately from
|
||||||
* {@link #isOpen()} as this method does not attempt any JTA synch
|
* {@link #isOpen()} as this method does not attempt any JTA synchronization
|
||||||
* registration, where as {@link #isOpen()} does; which makes this one
|
* registration, where as {@link #isOpen()} does; which makes this one
|
||||||
* nicer to use for most internal purposes.
|
* nicer to use for most internal purposes.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,19 +20,16 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine;
|
package org.hibernate.engine;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.jdbc.Work;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.engine.transaction.IsolatedWork;
|
|
||||||
import org.hibernate.engine.transaction.Isolater;
|
|
||||||
import org.hibernate.exception.JDBCExceptionHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows work to be done outside the current transaction, by suspending it,
|
* Allows work to be done outside the current transaction, by suspending it,
|
||||||
* and performing work in a new transaction
|
* and performing work in a new transaction
|
||||||
|
@ -41,7 +38,7 @@ import org.hibernate.exception.JDBCExceptionHelper;
|
||||||
*/
|
*/
|
||||||
public abstract class TransactionHelper {
|
public abstract class TransactionHelper {
|
||||||
|
|
||||||
// todo : remove this and just have subclasses use Isolater/IsolatedWork directly...
|
// todo : remove this and just have subclasses use IsolationDelegate directly...
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The work to be done
|
* The work to be done
|
||||||
|
@ -51,26 +48,27 @@ public abstract class TransactionHelper {
|
||||||
/**
|
/**
|
||||||
* Suspend the current transaction and perform work in a new transaction
|
* Suspend the current transaction and perform work in a new transaction
|
||||||
*/
|
*/
|
||||||
public Serializable doWorkInNewTransaction(final SessionImplementor session)
|
public Serializable doWorkInNewTransaction(final SessionImplementor session) throws HibernateException {
|
||||||
throws HibernateException {
|
class WorkToDo implements Work {
|
||||||
class Work implements IsolatedWork {
|
|
||||||
Serializable generatedValue;
|
Serializable generatedValue;
|
||||||
public void doWork(Connection connection) throws HibernateException {
|
|
||||||
|
@Override
|
||||||
|
public void execute(Connection connection) throws SQLException {
|
||||||
String sql = null;
|
String sql = null;
|
||||||
try {
|
try {
|
||||||
generatedValue = doWorkInCurrentTransaction( connection, sql );
|
generatedValue = doWorkInCurrentTransaction( connection, sql );
|
||||||
}
|
}
|
||||||
catch( SQLException sqle ) {
|
catch( SQLException e ) {
|
||||||
throw session.getFactory().getSQLExceptionHelper().convert(
|
throw session.getFactory().getSQLExceptionHelper().convert(
|
||||||
sqle,
|
e,
|
||||||
"could not get or update next value",
|
"could not get or update next value",
|
||||||
sql
|
sql
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Work work = new Work();
|
WorkToDo work = new WorkToDo();
|
||||||
Isolater.doIsolatedWork( work, session );
|
session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork( work, true );
|
||||||
return work.generatedValue;
|
return work.generatedValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,19 +23,20 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.jdbc.batch.internal;
|
package org.hibernate.engine.jdbc.batch.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||||
|
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||||
|
import org.hibernate.engine.jdbc.batch.spi.BatchObserver;
|
||||||
|
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||||
|
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
||||||
|
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
|
||||||
import org.hibernate.engine.jdbc.batch.spi.BatchObserver;
|
|
||||||
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
|
||||||
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience base class for implementors of the Batch interface.
|
* Convenience base class for implementors of the Batch interface.
|
||||||
*
|
*
|
||||||
|
@ -44,21 +45,20 @@ import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
||||||
public abstract class AbstractBatchImpl implements Batch {
|
public abstract class AbstractBatchImpl implements Batch {
|
||||||
private static final Logger log = LoggerFactory.getLogger( AbstractBatchImpl.class );
|
private static final Logger log = LoggerFactory.getLogger( AbstractBatchImpl.class );
|
||||||
|
|
||||||
private final SQLStatementLogger statementLogger;
|
private final BatchKey key;
|
||||||
private final SQLExceptionHelper exceptionHelper;
|
private final JdbcCoordinator jdbcCoordinator;
|
||||||
private Object key;
|
|
||||||
private LinkedHashMap<String,PreparedStatement> statements = new LinkedHashMap<String,PreparedStatement>();
|
private LinkedHashMap<String,PreparedStatement> statements = new LinkedHashMap<String,PreparedStatement>();
|
||||||
private LinkedHashSet<BatchObserver> observers = new LinkedHashSet<BatchObserver>();
|
private LinkedHashSet<BatchObserver> observers = new LinkedHashSet<BatchObserver>();
|
||||||
|
|
||||||
protected AbstractBatchImpl(Object key,
|
protected AbstractBatchImpl(BatchKey key, JdbcCoordinator jdbcCoordinator) {
|
||||||
SQLStatementLogger statementLogger,
|
if ( key == null ) {
|
||||||
SQLExceptionHelper exceptionHelper) {
|
throw new IllegalArgumentException( "batch key cannot be null" );
|
||||||
if ( key == null || statementLogger == null || exceptionHelper == null ) {
|
}
|
||||||
throw new IllegalArgumentException( "key, statementLogger, and exceptionHelper must be non-null." );
|
if ( jdbcCoordinator == null ) {
|
||||||
|
throw new IllegalArgumentException( "JDBC coordinator cannot be null" );
|
||||||
}
|
}
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.statementLogger = statementLogger;
|
this.jdbcCoordinator = jdbcCoordinator;
|
||||||
this.exceptionHelper = exceptionHelper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,8 +74,12 @@ public abstract class AbstractBatchImpl implements Batch {
|
||||||
*
|
*
|
||||||
* @return The underlying SQLException helper.
|
* @return The underlying SQLException helper.
|
||||||
*/
|
*/
|
||||||
protected SQLExceptionHelper getSqlExceptionHelper() {
|
protected SQLExceptionHelper sqlExceptionHelper() {
|
||||||
return exceptionHelper;
|
return jdbcCoordinator.getTransactionCoordinator()
|
||||||
|
.getTransactionContext()
|
||||||
|
.getTransactionEnvironment()
|
||||||
|
.getJdbcServices()
|
||||||
|
.getSqlExceptionHelper();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,8 +87,12 @@ public abstract class AbstractBatchImpl implements Batch {
|
||||||
*
|
*
|
||||||
* @return The underlying JDBC services.
|
* @return The underlying JDBC services.
|
||||||
*/
|
*/
|
||||||
protected SQLStatementLogger getSqlStatementLogger() {
|
protected SQLStatementLogger sqlStatementLogger() {
|
||||||
return statementLogger;
|
return jdbcCoordinator.getTransactionCoordinator()
|
||||||
|
.getTransactionContext()
|
||||||
|
.getTransactionEnvironment()
|
||||||
|
.getJdbcServices()
|
||||||
|
.getSqlStatementLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,62 +104,49 @@ public abstract class AbstractBatchImpl implements Batch {
|
||||||
return statements;
|
return statements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
public final BatchKey getKey() {
|
||||||
*/
|
|
||||||
public final Object getKey() {
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void addObserver(BatchObserver observer) {
|
public void addObserver(BatchObserver observer) {
|
||||||
observers.add( observer );
|
observers.add( observer );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
public PreparedStatement getBatchStatement(String sql, boolean callable) {
|
||||||
*/
|
|
||||||
public final PreparedStatement getBatchStatement(Object key, String sql) {
|
|
||||||
checkConsistentBatchKey( key );
|
|
||||||
if ( sql == null ) {
|
if ( sql == null ) {
|
||||||
throw new IllegalArgumentException( "sql must be non-null." );
|
throw new IllegalArgumentException( "sql must be non-null." );
|
||||||
}
|
}
|
||||||
PreparedStatement statement = statements.get( sql );
|
PreparedStatement statement = statements.get( sql );
|
||||||
if ( statement != null ) {
|
if ( statement == null ) {
|
||||||
log.debug( "reusing prepared statement" );
|
statement = buildBatchStatement( sql, callable );
|
||||||
statementLogger.logStatement( sql );
|
statements.put( sql, statement );
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
log.debug( "reusing batch statement" );
|
||||||
|
sqlStatementLogger().logStatement( sql );
|
||||||
|
}
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private PreparedStatement buildBatchStatement(String sql, boolean callable) {
|
||||||
* {@inheritDoc}
|
try {
|
||||||
*/
|
if ( callable ) {
|
||||||
// TODO: should this be final???
|
return jdbcCoordinator.getLogicalConnection().getShareableConnectionProxy().prepareCall( sql );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return jdbcCoordinator.getLogicalConnection().getShareableConnectionProxy().prepareStatement( sql );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( SQLException sqle ) {
|
||||||
|
log.error( "sqlexception escaped proxy", sqle );
|
||||||
|
throw sqlExceptionHelper().convert( sqle, "could not prepare batch statement", sql );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement) {
|
|
||||||
checkConsistentBatchKey( key );
|
|
||||||
if ( sql == null ) {
|
|
||||||
throw new IllegalArgumentException( "sql must be non-null." );
|
|
||||||
}
|
|
||||||
if ( statements.put( sql, preparedStatement ) != null ) {
|
|
||||||
log.error( "PreparedStatement was already in the batch, [" + sql + "]." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void checkConsistentBatchKey(Object key) {
|
|
||||||
if ( ! this.key.equals( key ) ) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"specified key ["+ key + "] is different from internal batch key [" + this.key + "]."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public final void execute() {
|
public final void execute() {
|
||||||
notifyObserversExplicitExecution();
|
notifyObserversExplicitExecution();
|
||||||
if ( statements.isEmpty() ) {
|
if ( statements.isEmpty() ) {
|
||||||
|
@ -162,7 +157,7 @@ public abstract class AbstractBatchImpl implements Batch {
|
||||||
doExecuteBatch();
|
doExecuteBatch();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
release();
|
releaseStatements();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -176,14 +171,16 @@ public abstract class AbstractBatchImpl implements Batch {
|
||||||
statement.close();
|
statement.close();
|
||||||
}
|
}
|
||||||
catch ( SQLException e ) {
|
catch ( SQLException e ) {
|
||||||
log.error( "unable to release batch statement..." );
|
log.error( "unable to release batch statement; sqlexception escaped proxy", e );
|
||||||
log.error( "sqlexception escaped proxy", e );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getStatements().clear();
|
getStatements().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyObserversExplicitExecution() {
|
/**
|
||||||
|
* Convenience method to notify registered observers of an explicit execution of this batch.
|
||||||
|
*/
|
||||||
|
protected final void notifyObserversExplicitExecution() {
|
||||||
for ( BatchObserver observer : observers ) {
|
for ( BatchObserver observer : observers ) {
|
||||||
observer.batchExplicitlyExecuted();
|
observer.batchExplicitlyExecuted();
|
||||||
}
|
}
|
||||||
|
@ -192,12 +189,13 @@ public abstract class AbstractBatchImpl implements Batch {
|
||||||
/**
|
/**
|
||||||
* Convenience method to notify registered observers of an implicit execution of this batch.
|
* Convenience method to notify registered observers of an implicit execution of this batch.
|
||||||
*/
|
*/
|
||||||
protected void notifyObserversImplicitExecution() {
|
protected final void notifyObserversImplicitExecution() {
|
||||||
for ( BatchObserver observer : observers ) {
|
for ( BatchObserver observer : observers ) {
|
||||||
observer.batchImplicitlyExecuted();
|
observer.batchImplicitlyExecuted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
if ( getStatements() != null && !getStatements().isEmpty() ) {
|
if ( getStatements() != null && !getStatements().isEmpty() ) {
|
||||||
log.info( "On release of batch it still contained JDBC statements" );
|
log.info( "On release of batch it still contained JDBC statements" );
|
||||||
|
|
|
@ -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;
|
package org.hibernate.engine.jdbc.batch.internal;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||||
|
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
|
||||||
|
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||||
|
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||||
|
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
|
import org.hibernate.service.spi.Configurable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
import java.util.Map;
|
||||||
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
|
|
||||||
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
|
||||||
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder for {@link Batch} instances.
|
* A builder for {@link Batch} instances.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class BatchBuilder {
|
public class BatchBuilderImpl implements BatchBuilder, Configurable {
|
||||||
private static final Logger log = LoggerFactory.getLogger( BatchBuilder.class );
|
private static final Logger log = LoggerFactory.getLogger( BatchBuilderImpl.class );
|
||||||
|
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
public BatchBuilder() {
|
public BatchBuilderImpl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public BatchBuilder(int size) {
|
@Override
|
||||||
|
public void configure(Map configurationValues) {
|
||||||
|
size = ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, size );
|
||||||
|
}
|
||||||
|
|
||||||
|
public BatchBuilderImpl(int size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,13 +61,27 @@ public class BatchBuilder {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Batch buildBatch(Object key,
|
@Override
|
||||||
SQLStatementLogger statementLogger,
|
public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) {
|
||||||
SQLExceptionHelper exceptionHelper) {
|
|
||||||
log.trace( "building batch [size={}]", size );
|
log.trace( "building batch [size={}]", size );
|
||||||
return size > 1
|
return size > 1
|
||||||
? new BatchingBatch( key, statementLogger, exceptionHelper, size )
|
? new BatchingBatch( key, jdbcCoordinator, size )
|
||||||
: new NonBatchingBatch( key, statementLogger, exceptionHelper );
|
: new NonBatchingBatch( key, jdbcCoordinator );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getManagementDomain() {
|
||||||
|
return null; // use Hibernate default domain
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getManagementServiceType() {
|
||||||
|
return null; // use Hibernate default scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getManagementBean() {
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.hibernate.engine.jdbc.batch.internal;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import org.hibernate.HibernateException;
|
||||||
import java.sql.SQLException;
|
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||||
import java.util.ArrayList;
|
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import java.sql.PreparedStatement;
|
||||||
import org.hibernate.HibernateException;
|
import java.sql.SQLException;
|
||||||
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
import java.util.Map;
|
||||||
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
|
||||||
import org.hibernate.jdbc.Expectation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does
|
* A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does bathing based on a given size. Once
|
||||||
* batching based on a given size. Once the batch size is reached for a statement
|
* the batch size is reached for a statement in the batch, the entire batch is implicitly executed.
|
||||||
* in the batch, the entire batch is implicitly executed.
|
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class BatchingBatch extends AbstractBatchImpl {
|
public class BatchingBatch extends AbstractBatchImpl {
|
||||||
private static final Logger log = LoggerFactory.getLogger( BatchingBatch.class );
|
private static final Logger log = LoggerFactory.getLogger( BatchingBatch.class );
|
||||||
|
|
||||||
|
// IMPL NOTE : Until HHH-5797 is fixed, there will only be 1 statement in a batch
|
||||||
|
|
||||||
private final int batchSize;
|
private final int batchSize;
|
||||||
|
private int batchPosition;
|
||||||
|
private int statementPosition;
|
||||||
|
|
||||||
// TODO: A Map is used for expectations so it is possible to track when a batch
|
public BatchingBatch(
|
||||||
// is full (i.e., when the batch for a particular statement exceeds batchSize)
|
BatchKey key,
|
||||||
// Until HHH-5797 is fixed, there will only be 1 statement in a batch, so it won't
|
JdbcCoordinator jdbcCoordinator,
|
||||||
// be necessary to track expectations by statement.
|
int batchSize) {
|
||||||
private Map<String, List<Expectation>> expectationsBySql;
|
super( key, jdbcCoordinator );
|
||||||
private int maxBatchPosition;
|
if ( ! key.getExpectation().canBeBatched() ) {
|
||||||
|
|
||||||
public BatchingBatch(Object key,
|
|
||||||
SQLStatementLogger statementLogger,
|
|
||||||
SQLExceptionHelper exceptionHelper,
|
|
||||||
int batchSize) {
|
|
||||||
super( key, statementLogger, exceptionHelper );
|
|
||||||
this.batchSize = batchSize;
|
|
||||||
this.expectationsBySql = new HashMap<String, List<Expectation>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void addToBatch(Object key, String sql, Expectation expectation) {
|
|
||||||
checkConsistentBatchKey( key );
|
|
||||||
if ( sql == null || expectation == null ) {
|
|
||||||
throw new AssertionFailure( "sql or expection was null." );
|
|
||||||
}
|
|
||||||
if ( ! expectation.canBeBatched() ) {
|
|
||||||
throw new HibernateException( "attempting to batch an operation which cannot be batched" );
|
throw new HibernateException( "attempting to batch an operation which cannot be batched" );
|
||||||
}
|
}
|
||||||
final PreparedStatement statement = getStatements().get( sql );
|
this.batchSize = batchSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentStatementSql;
|
||||||
|
private PreparedStatement currentStatement;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreparedStatement getBatchStatement(String sql, boolean callable) {
|
||||||
|
currentStatementSql = sql;
|
||||||
|
currentStatement = super.getBatchStatement( sql, callable );
|
||||||
|
return currentStatement;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addToBatch() {
|
||||||
try {
|
try {
|
||||||
statement.addBatch();
|
currentStatement.addBatch();
|
||||||
}
|
}
|
||||||
catch ( SQLException e ) {
|
catch ( SQLException e ) {
|
||||||
log.error( "sqlexception escaped proxy", e );
|
log.debug( "sqlexception escaped proxy", e );
|
||||||
throw getSqlExceptionHelper().convert( e, "could not perform addBatch", sql );
|
throw sqlExceptionHelper().convert( e, "could not perform addBatch", currentStatementSql );
|
||||||
}
|
}
|
||||||
List<Expectation> expectations = expectationsBySql.get( sql );
|
statementPosition++;
|
||||||
if ( expectations == null ) {
|
if ( statementPosition >= getKey().getBatchedStatementCount() ) {
|
||||||
expectations = new ArrayList<Expectation>( batchSize );
|
batchPosition++;
|
||||||
expectationsBySql.put( sql, expectations );
|
if ( batchPosition == batchSize ) {
|
||||||
}
|
notifyObserversImplicitExecution();
|
||||||
expectations.add( expectation );
|
performExecution();
|
||||||
maxBatchPosition = Math.max( maxBatchPosition, expectations.size() );
|
batchPosition = 0;
|
||||||
|
}
|
||||||
// TODO: When HHH-5797 is fixed the following if-block should probably be moved before
|
statementPosition = 0;
|
||||||
// adding the batch to the current statement (to detect that we have finished
|
|
||||||
// with the previous entity).
|
|
||||||
if ( maxBatchPosition == batchSize ) {
|
|
||||||
notifyObserversImplicitExecution();
|
|
||||||
doExecuteBatch();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
protected void doExecuteBatch() {
|
protected void doExecuteBatch() {
|
||||||
if ( maxBatchPosition == 0 ) {
|
if ( batchPosition == 0 ) {
|
||||||
log.debug( "no batched statements to execute" );
|
log.debug( "no batched statements to execute" );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( log.isDebugEnabled() ) {
|
if ( log.isDebugEnabled() ) {
|
||||||
log.debug( "Executing {} statements with maximum batch size {} ",
|
log.debug( "Executing batch size: " + batchPosition );
|
||||||
getStatements().size(), maxBatchPosition
|
|
||||||
);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
executeStatements();
|
|
||||||
}
|
|
||||||
catch ( RuntimeException re ) {
|
|
||||||
log.error( "Exception executing batch [{}]", re.getMessage() );
|
|
||||||
throw re;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
for ( List<Expectation> expectations : expectationsBySql.values() ) {
|
|
||||||
expectations.clear();
|
|
||||||
}
|
|
||||||
maxBatchPosition = 0;
|
|
||||||
}
|
}
|
||||||
|
performExecution();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeStatements() {
|
private void performExecution() {
|
||||||
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
|
|
||||||
final String sql = entry.getKey();
|
|
||||||
final PreparedStatement statement = entry.getValue();
|
|
||||||
final List<Expectation> expectations = expectationsBySql.get( sql );
|
|
||||||
if ( batchSize < expectations.size() ) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Number of expectations [" + expectations.size() +
|
|
||||||
"] is greater than batch size [" + batchSize +
|
|
||||||
"] for statement [" + sql +
|
|
||||||
"]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ( expectations.size() > 0 ) {
|
|
||||||
if ( log.isDebugEnabled() ) {
|
|
||||||
log.debug( "Executing with batch of size {}: {}", expectations.size(), sql );
|
|
||||||
}
|
|
||||||
executeStatement( sql, statement, expectations );
|
|
||||||
expectations.clear();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( log.isDebugEnabled() ) {
|
|
||||||
log.debug( "Skipped executing because batch size is 0: ", sql );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void executeStatement(String sql, PreparedStatement ps, List<Expectation> expectations) {
|
|
||||||
try {
|
try {
|
||||||
checkRowCounts( sql, ps.executeBatch(), ps, expectations );
|
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
|
||||||
|
try {
|
||||||
|
final PreparedStatement statement = entry.getValue();
|
||||||
|
checkRowCounts( statement.executeBatch(), statement );
|
||||||
|
}
|
||||||
|
catch ( SQLException e ) {
|
||||||
|
log.debug( "sqlexception escaped proxy", e );
|
||||||
|
throw sqlExceptionHelper().convert( e, "could not perform addBatch", entry.getKey() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch ( SQLException e ) {
|
catch ( RuntimeException re ) {
|
||||||
log.error( "sqlexception escaped proxy", e );
|
log.error( "Exception executing batch [{}]", re.getMessage() );
|
||||||
throw getSqlExceptionHelper()
|
throw re;
|
||||||
.convert( e, "could not execute statement: " + sql );
|
}
|
||||||
|
finally {
|
||||||
|
batchPosition = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkRowCounts(String sql, int[] rowCounts, PreparedStatement ps, List<Expectation> expectations) {
|
private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException {
|
||||||
int numberOfRowCounts = rowCounts.length;
|
int numberOfRowCounts = rowCounts.length;
|
||||||
if ( numberOfRowCounts != expectations.size() ) {
|
if ( numberOfRowCounts != batchPosition ) {
|
||||||
log.warn( "JDBC driver did not return the expected number of row counts" );
|
log.warn( "JDBC driver did not return the expected number of row counts" );
|
||||||
}
|
}
|
||||||
try {
|
for ( int i = 0; i < numberOfRowCounts; i++ ) {
|
||||||
for ( int i = 0; i < numberOfRowCounts; i++ ) {
|
getKey().getExpectation().verifyOutcome( rowCounts[i], ps, i );
|
||||||
expectations.get( i ).verifyOutcome( rowCounts[i], ps, i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( SQLException e ) {
|
|
||||||
log.error( "sqlexception escaped proxy", e );
|
|
||||||
throw getSqlExceptionHelper()
|
|
||||||
.convert( e, "row count verification failed for statement: ", sql );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void release() {
|
|
||||||
expectationsBySql.clear();
|
|
||||||
maxBatchPosition = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -23,48 +23,52 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.jdbc.batch.internal;
|
package org.hibernate.engine.jdbc.batch.internal;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||||
import java.sql.SQLException;
|
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
import java.sql.PreparedStatement;
|
||||||
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
import java.sql.SQLException;
|
||||||
import org.hibernate.jdbc.Expectation;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of {@link org.hibernate.engine.jdbc.batch.spi.Batch} which does not perform batching. It simply executes each statement as it is
|
* An implementation of {@link org.hibernate.engine.jdbc.batch.spi.Batch} which does not perform batching. It simply
|
||||||
* encountered.
|
* executes each statement as it is encountered.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class NonBatchingBatch extends AbstractBatchImpl {
|
public class NonBatchingBatch extends AbstractBatchImpl {
|
||||||
private static final Logger log = LoggerFactory.getLogger( NonBatchingBatch.class );
|
private static final Logger log = LoggerFactory.getLogger( NonBatchingBatch.class );
|
||||||
|
|
||||||
protected NonBatchingBatch(Object key,
|
protected NonBatchingBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) {
|
||||||
SQLStatementLogger statementLogger,
|
super( key, jdbcCoordinator );
|
||||||
SQLExceptionHelper exceptionHelper) {
|
|
||||||
super( key, statementLogger, exceptionHelper );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addToBatch(Object key, String sql, Expectation expectation) {
|
@Override
|
||||||
checkConsistentBatchKey( key );
|
public void addToBatch() {
|
||||||
if ( sql == null ) {
|
|
||||||
throw new IllegalArgumentException( "sql must be non-null." );
|
|
||||||
}
|
|
||||||
notifyObserversImplicitExecution();
|
notifyObserversImplicitExecution();
|
||||||
try {
|
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
|
||||||
final PreparedStatement statement = getStatements().get( sql );
|
try {
|
||||||
final int rowCount = statement.executeUpdate();
|
final PreparedStatement statement = entry.getValue();
|
||||||
expectation.verifyOutcome( rowCount, statement, 0 );
|
final int rowCount = statement.executeUpdate();
|
||||||
}
|
getKey().getExpectation().verifyOutcome( rowCount, statement, 0 );
|
||||||
catch ( SQLException e ) {
|
try {
|
||||||
log.error( "sqlexception escaped proxy", e );
|
statement.close();
|
||||||
throw getSqlExceptionHelper().convert( e, "could not execute batch statement", sql );
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
log.debug( "Unable to close non-batched batch statement", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( SQLException e ) {
|
||||||
|
log.debug( "sqlexception escaped proxy", e );
|
||||||
|
throw sqlExceptionHelper().convert( e, "could not execute batch statement", entry.getKey() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
getStatements().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void doExecuteBatch() {
|
protected void doExecuteBatch() {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public interface Batch {
|
||||||
*
|
*
|
||||||
* @return The batch key.
|
* @return The batch key.
|
||||||
*/
|
*/
|
||||||
public Object getKey();
|
public BatchKey getKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an observer to this batch.
|
* Adds an observer to this batch.
|
||||||
|
@ -52,30 +52,19 @@ public interface Batch {
|
||||||
public void addObserver(BatchObserver observer);
|
public void addObserver(BatchObserver observer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a statement which is part of the batch.
|
* Get a statement which is part of the batch, creating if necessary (and storing for next time).
|
||||||
*
|
*
|
||||||
* @param sql The SQL statement.
|
* @param sql The SQL statement.
|
||||||
* @return the prepared statement representing the SQL statement, if the batch contained it;
|
* @param callable Is the SQL statement callable?
|
||||||
* null, otherwise.
|
|
||||||
*/
|
|
||||||
public PreparedStatement getBatchStatement(Object key, String sql);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a prepared statement to the batch.
|
|
||||||
*
|
*
|
||||||
* @param sql The SQL statement.
|
* @return The prepared statement instance, representing the SQL statement.
|
||||||
*/
|
*/
|
||||||
public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement);
|
public PreparedStatement getBatchStatement(String sql, boolean callable);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates completion of the current part of the batch.
|
* Indicates completion of the current part of the batch.
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param sql
|
|
||||||
* @param expectation The expectation for the part's result.
|
|
||||||
*/
|
*/
|
||||||
public void addToBatch(Object key, String sql, Expectation expectation);
|
public void addToBatch();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute this batch.
|
* Execute this batch.
|
||||||
|
|
|
@ -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
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,29 +20,30 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction;
|
package org.hibernate.engine.jdbc.batch.spi;
|
||||||
|
|
||||||
|
import org.hibernate.jdbc.Expectation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link TransactionManagerLookup} strategy for Resin
|
* Unique key for batch identification.
|
||||||
*
|
*
|
||||||
* @author Aapo Laakkonen
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ResinTransactionManagerLookup extends JNDITransactionManagerLookup {
|
public interface BatchKey {
|
||||||
|
/**
|
||||||
|
* How many statements will be in this batch?
|
||||||
|
* <p/>
|
||||||
|
* Note that this is distinctly different than the size of the batch.
|
||||||
|
*
|
||||||
|
* @return The number of statements.
|
||||||
|
*/
|
||||||
|
public int getBatchedStatementCount();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* Get the expectation pertaining to the outcome of the {@link Batch} associated with this key.
|
||||||
|
*
|
||||||
|
* @return The expectations
|
||||||
*/
|
*/
|
||||||
protected String getName() {
|
public Expectation getExpectation();
|
||||||
return "java:comp/TransactionManager";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public String getUserTransactionName() {
|
|
||||||
return "java:comp/UserTransaction";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
package org.hibernate.engine.jdbc.internal;
|
||||||
|
|
||||||
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.JDBCException;
|
||||||
|
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
|
||||||
|
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
|
||||||
|
import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
|
||||||
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
|
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
|
||||||
|
import org.hibernate.engine.jdbc.spi.NonDurableConnectionObserver;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionContext;
|
||||||
|
import org.hibernate.util.CollectionHelper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
|
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|
||||||
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
|
|
||||||
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
|
|
||||||
import org.hibernate.jdbc.BorrowedConnectionProxy;
|
|
||||||
import org.hibernate.stat.StatisticsImplementor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LogicalConnectionImpl implementation
|
* Standard Hibernate {@link org.hibernate.engine.jdbc.spi.LogicalConnection} implementation
|
||||||
|
* <p/>
|
||||||
|
* IMPL NOTE : Custom serialization handling!
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
private static final Logger log = LoggerFactory.getLogger( LogicalConnectionImpl.class );
|
private static final Logger log = LoggerFactory.getLogger( LogicalConnectionImpl.class );
|
||||||
|
|
||||||
private Connection physicalConnection;
|
private transient Connection physicalConnection;
|
||||||
private Connection borrowedConnection;
|
private transient Connection shareableConnectionProxy;
|
||||||
|
|
||||||
private final ConnectionReleaseMode connectionReleaseMode;
|
private final transient ConnectionReleaseMode connectionReleaseMode;
|
||||||
private final JdbcServices jdbcServices;
|
private final transient JdbcServices jdbcServices;
|
||||||
private final StatisticsImplementor statisticsImplementor;
|
private final transient JdbcResourceRegistry jdbcResourceRegistry;
|
||||||
private final JdbcResourceRegistry jdbcResourceRegistry;
|
private final transient List<ConnectionObserver> observers;
|
||||||
private final List<ConnectionObserver> observers = new ArrayList<ConnectionObserver>();
|
|
||||||
|
|
||||||
private boolean releasesEnabled = true;
|
private boolean releasesEnabled = true;
|
||||||
|
|
||||||
|
@ -67,40 +70,41 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
|
|
||||||
private boolean isClosed;
|
private boolean isClosed;
|
||||||
|
|
||||||
public LogicalConnectionImpl(Connection userSuppliedConnection,
|
public LogicalConnectionImpl(
|
||||||
ConnectionReleaseMode connectionReleaseMode,
|
Connection userSuppliedConnection,
|
||||||
JdbcServices jdbcServices,
|
ConnectionReleaseMode connectionReleaseMode,
|
||||||
StatisticsImplementor statisticsImplementor
|
JdbcServices jdbcServices) {
|
||||||
) {
|
this(
|
||||||
this( connectionReleaseMode,
|
connectionReleaseMode,
|
||||||
jdbcServices,
|
jdbcServices,
|
||||||
statisticsImplementor,
|
(userSuppliedConnection != null),
|
||||||
userSuppliedConnection != null,
|
false,
|
||||||
false
|
new ArrayList<ConnectionObserver>()
|
||||||
);
|
);
|
||||||
this.physicalConnection = userSuppliedConnection;
|
this.physicalConnection = userSuppliedConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LogicalConnectionImpl(ConnectionReleaseMode connectionReleaseMode,
|
private LogicalConnectionImpl(
|
||||||
JdbcServices jdbcServices,
|
ConnectionReleaseMode connectionReleaseMode,
|
||||||
StatisticsImplementor statisticsImplementor,
|
JdbcServices jdbcServices,
|
||||||
boolean isUserSuppliedConnection,
|
boolean isUserSuppliedConnection,
|
||||||
boolean isClosed) {
|
boolean isClosed,
|
||||||
|
List<ConnectionObserver> observers) {
|
||||||
this.connectionReleaseMode = determineConnectionReleaseMode(
|
this.connectionReleaseMode = determineConnectionReleaseMode(
|
||||||
jdbcServices, isUserSuppliedConnection, connectionReleaseMode
|
jdbcServices, isUserSuppliedConnection, connectionReleaseMode
|
||||||
);
|
);
|
||||||
this.jdbcServices = jdbcServices;
|
this.jdbcServices = jdbcServices;
|
||||||
this.statisticsImplementor = statisticsImplementor;
|
this.jdbcResourceRegistry = new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() );
|
||||||
this.jdbcResourceRegistry =
|
this.observers = observers;
|
||||||
new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() );
|
|
||||||
|
|
||||||
this.isUserSuppliedConnection = isUserSuppliedConnection;
|
this.isUserSuppliedConnection = isUserSuppliedConnection;
|
||||||
this.isClosed = isClosed;
|
this.isClosed = isClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ConnectionReleaseMode determineConnectionReleaseMode(JdbcServices jdbcServices,
|
private static ConnectionReleaseMode determineConnectionReleaseMode(
|
||||||
boolean isUserSuppliedConnection,
|
JdbcServices jdbcServices,
|
||||||
ConnectionReleaseMode connectionReleaseMode) {
|
boolean isUserSuppliedConnection,
|
||||||
|
ConnectionReleaseMode connectionReleaseMode) {
|
||||||
if ( isUserSuppliedConnection ) {
|
if ( isUserSuppliedConnection ) {
|
||||||
return ConnectionReleaseMode.ON_CLOSE;
|
return ConnectionReleaseMode.ON_CLOSE;
|
||||||
}
|
}
|
||||||
|
@ -114,60 +118,37 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public JdbcServices getJdbcServices() {
|
public JdbcServices getJdbcServices() {
|
||||||
return jdbcServices;
|
return jdbcServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public StatisticsImplementor getStatisticsImplementor() {
|
|
||||||
return statisticsImplementor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public JdbcResourceRegistry getResourceRegistry() {
|
public JdbcResourceRegistry getResourceRegistry() {
|
||||||
return jdbcResourceRegistry;
|
return jdbcResourceRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void addObserver(ConnectionObserver observer) {
|
public void addObserver(ConnectionObserver observer) {
|
||||||
observers.add( observer );
|
observers.add( observer );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
public void removeObserver(ConnectionObserver connectionObserver) {
|
||||||
*/
|
observers.remove( connectionObserver );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isOpen() {
|
public boolean isOpen() {
|
||||||
return !isClosed;
|
return !isClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public boolean isLogicallyConnected() {
|
|
||||||
return isUserSuppliedConnection ?
|
|
||||||
isPhysicallyConnected() :
|
|
||||||
isOpen();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public boolean isPhysicallyConnected() {
|
public boolean isPhysicallyConnected() {
|
||||||
return physicalConnection != null;
|
return physicalConnection != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public Connection getConnection() throws HibernateException {
|
public Connection getConnection() throws HibernateException {
|
||||||
if ( isClosed ) {
|
if ( isClosed ) {
|
||||||
throw new HibernateException( "Logical connection is closed" );
|
throw new HibernateException( "Logical connection is closed" );
|
||||||
|
@ -182,16 +163,33 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
return physicalConnection;
|
return physicalConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection getShareableConnectionProxy() {
|
||||||
|
if ( shareableConnectionProxy == null ) {
|
||||||
|
shareableConnectionProxy = buildConnectionProxy();
|
||||||
|
}
|
||||||
|
return shareableConnectionProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Connection buildConnectionProxy() {
|
||||||
|
return ProxyBuilder.buildConnection( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection getDistinctConnectionProxy() {
|
||||||
|
return buildConnectionProxy();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public Connection close() {
|
public Connection close() {
|
||||||
Connection c = physicalConnection;
|
log.trace( "closing logical connection" );
|
||||||
|
Connection c = isUserSuppliedConnection ? physicalConnection : null;
|
||||||
try {
|
try {
|
||||||
releaseBorrowedConnection();
|
releaseProxies();
|
||||||
log.trace( "closing logical connection" );
|
jdbcResourceRegistry.close();
|
||||||
if ( !isUserSuppliedConnection && physicalConnection != null ) {
|
if ( !isUserSuppliedConnection && physicalConnection != null ) {
|
||||||
jdbcResourceRegistry.close();
|
|
||||||
releaseConnection();
|
releaseConnection();
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
|
@ -204,46 +202,28 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
for ( ConnectionObserver observer : observers ) {
|
for ( ConnectionObserver observer : observers ) {
|
||||||
observer.logicalConnectionClosed();
|
observer.logicalConnectionClosed();
|
||||||
}
|
}
|
||||||
|
observers.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void releaseProxies() {
|
||||||
* {@inheritDoc}
|
if ( shareableConnectionProxy != null ) {
|
||||||
*/
|
try {
|
||||||
|
shareableConnectionProxy.close();
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
log.debug( "Error releasing shared connection proxy", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shareableConnectionProxy = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ConnectionReleaseMode getConnectionReleaseMode() {
|
public ConnectionReleaseMode getConnectionReleaseMode() {
|
||||||
return connectionReleaseMode;
|
return connectionReleaseMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasBorrowedConnection() {
|
@Override
|
||||||
return borrowedConnection != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Connection borrowConnection() {
|
|
||||||
if ( isClosed ) {
|
|
||||||
throw new HibernateException( "connection has been closed" );
|
|
||||||
}
|
|
||||||
if ( isUserSuppliedConnection ) {
|
|
||||||
return physicalConnection;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( borrowedConnection == null ) {
|
|
||||||
borrowedConnection = BorrowedConnectionProxy.generateProxy( this );
|
|
||||||
}
|
|
||||||
return borrowedConnection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void releaseBorrowedConnection() {
|
|
||||||
if ( borrowedConnection != null ) {
|
|
||||||
try {
|
|
||||||
BorrowedConnectionProxy.renderUnuseable( borrowedConnection );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
borrowedConnection = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void afterStatementExecution() {
|
public void afterStatementExecution() {
|
||||||
log.trace( "starting after statement execution processing [{}]", connectionReleaseMode );
|
log.trace( "starting after statement execution processing [{}]", connectionReleaseMode );
|
||||||
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
|
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
|
||||||
|
@ -255,13 +235,11 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
log.debug( "skipping aggressive release due to registered resources" );
|
log.debug( "skipping aggressive release due to registered resources" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if ( borrowedConnection != null ) {
|
|
||||||
log.debug( "skipping aggresive-release due to borrowed connection" );
|
|
||||||
}
|
|
||||||
releaseConnection();
|
releaseConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void afterTransaction() {
|
public void afterTransaction() {
|
||||||
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ||
|
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ||
|
||||||
connectionReleaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
|
connectionReleaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
|
||||||
|
@ -273,20 +251,21 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void disableReleases() {
|
public void disableReleases() {
|
||||||
log.trace( "disabling releases" );
|
log.trace( "disabling releases" );
|
||||||
releasesEnabled = false;
|
releasesEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void enableReleases() {
|
public void enableReleases() {
|
||||||
log.trace( "(re)enabling releases" );
|
log.trace( "(re)enabling releases" );
|
||||||
releasesEnabled = true;
|
releasesEnabled = true;
|
||||||
//FIXME: uncomment after new batch stuff is integrated!!!
|
afterStatementExecution();
|
||||||
//afterStatementExecution();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force aggresive release of the underlying connection.
|
* Force aggressive release of the underlying connection.
|
||||||
*/
|
*/
|
||||||
public void aggressiveRelease() {
|
public void aggressiveRelease() {
|
||||||
if ( isUserSuppliedConnection ) {
|
if ( isUserSuppliedConnection ) {
|
||||||
|
@ -302,7 +281,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pysically opens a JDBC Connection.
|
* Physically opens a JDBC Connection.
|
||||||
*
|
*
|
||||||
* @throws org.hibernate.JDBCException Indicates problem opening a connection
|
* @throws org.hibernate.JDBCException Indicates problem opening a connection
|
||||||
*/
|
*/
|
||||||
|
@ -349,32 +328,32 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
for ( ConnectionObserver observer : observers ) {
|
for ( ConnectionObserver observer : observers ) {
|
||||||
observer.physicalConnectionReleased();
|
observer.physicalConnectionReleased();
|
||||||
}
|
}
|
||||||
|
releaseNonDurableObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Manually disconnect the underlying JDBC Connection. The assumption here
|
|
||||||
* is that the manager will be reconnected at a later point in time.
|
|
||||||
*
|
|
||||||
* @return The connection mantained here at time of disconnect. Null if
|
|
||||||
* there was no connection cached internally.
|
|
||||||
*/
|
|
||||||
public Connection manualDisconnect() {
|
public Connection manualDisconnect() {
|
||||||
if ( isClosed ) {
|
if ( isClosed ) {
|
||||||
throw new IllegalStateException( "cannot manually disconnect because logical connection is already closed" );
|
throw new IllegalStateException( "cannot manually disconnect because logical connection is already closed" );
|
||||||
}
|
}
|
||||||
|
releaseProxies();
|
||||||
Connection c = physicalConnection;
|
Connection c = physicalConnection;
|
||||||
jdbcResourceRegistry.releaseResources();
|
jdbcResourceRegistry.releaseResources();
|
||||||
releaseConnection();
|
releaseConnection();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void releaseNonDurableObservers() {
|
||||||
* Manually reconnect the underlying JDBC Connection. Should be called at
|
Iterator observers = this.observers.iterator();
|
||||||
* some point after manualDisconnect().
|
while ( observers.hasNext() ) {
|
||||||
* <p/>
|
if ( NonDurableConnectionObserver.class.isInstance( observers.next() ) ) {
|
||||||
* This form is used for user-supplied connections.
|
observers.remove();
|
||||||
*/
|
}
|
||||||
public void reconnect(Connection suppliedConnection) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void manualReconnect(Connection suppliedConnection) {
|
||||||
if ( isClosed ) {
|
if ( isClosed ) {
|
||||||
throw new IllegalStateException( "cannot manually reconnect because logical connection is already closed" );
|
throw new IllegalStateException( "cannot manually reconnect because logical connection is already closed" );
|
||||||
}
|
}
|
||||||
|
@ -401,29 +380,65 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAutoCommit() {
|
||||||
|
if ( !isOpen() || ! isPhysicallyConnected() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return getConnection().getAutoCommit();
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
throw jdbcServices.getSqlExceptionHelper().convert( e, "could not inspect JDBC autocommit mode" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyObserversStatementPrepared() {
|
||||||
|
for ( ConnectionObserver observer : observers ) {
|
||||||
|
observer.statementPrepared();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isReadyForSerialization() {
|
public boolean isReadyForSerialization() {
|
||||||
return isUserSuppliedConnection ?
|
return isUserSuppliedConnection
|
||||||
! isPhysicallyConnected() :
|
? ! isPhysicallyConnected()
|
||||||
! getResourceRegistry().hasRegisteredResources()
|
: ! getResourceRegistry().hasRegisteredResources();
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void serialize(ObjectOutputStream oos) throws IOException {
|
public void serialize(ObjectOutputStream oos) throws IOException {
|
||||||
oos.writeBoolean( isUserSuppliedConnection );
|
oos.writeBoolean( isUserSuppliedConnection );
|
||||||
oos.writeBoolean( isClosed );
|
oos.writeBoolean( isClosed );
|
||||||
|
List<ConnectionObserver> durableConnectionObservers = new ArrayList<ConnectionObserver>();
|
||||||
|
for ( ConnectionObserver observer : observers ) {
|
||||||
|
if ( ! NonDurableConnectionObserver.class.isInstance( observer ) ) {
|
||||||
|
durableConnectionObservers.add( observer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oos.writeInt( durableConnectionObservers.size() );
|
||||||
|
for ( ConnectionObserver observer : durableConnectionObservers ) {
|
||||||
|
oos.writeObject( observer );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LogicalConnectionImpl deserialize(ObjectInputStream ois,
|
public static LogicalConnectionImpl deserialize(
|
||||||
JdbcServices jdbcServices,
|
ObjectInputStream ois,
|
||||||
StatisticsImplementor statisticsImplementor,
|
TransactionContext transactionContext) throws IOException, ClassNotFoundException {
|
||||||
ConnectionReleaseMode connectionReleaseMode
|
boolean isUserSuppliedConnection = ois.readBoolean();
|
||||||
) throws IOException {
|
boolean isClosed = ois.readBoolean();
|
||||||
|
int observerCount = ois.readInt();
|
||||||
|
List<ConnectionObserver> observers = CollectionHelper.arrayList( observerCount );
|
||||||
|
for ( int i = 0; i < observerCount; i++ ) {
|
||||||
|
observers.add( (ConnectionObserver) ois.readObject() );
|
||||||
|
}
|
||||||
return new LogicalConnectionImpl(
|
return new LogicalConnectionImpl(
|
||||||
connectionReleaseMode,
|
transactionContext.getConnectionReleaseMode(),
|
||||||
jdbcServices,
|
transactionContext.getTransactionEnvironment().getJdbcServices(),
|
||||||
statisticsImplementor,
|
isUserSuppliedConnection,
|
||||||
ois.readBoolean(),
|
isClosed,
|
||||||
ois.readBoolean()
|
observers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.TransactionException;
|
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
|
import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
|
|
||||||
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
|
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
|
||||||
import org.hibernate.stat.StatisticsImplementor;
|
import org.hibernate.engine.jdbc.spi.NonDurableConnectionObserver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link InvocationHandler} for intercepting messages to {@link java.sql.Connection} proxies.
|
* The {@link InvocationHandler} for intercepting messages to {@link java.sql.Connection} proxies.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ConnectionProxyHandler extends AbstractProxyHandler implements InvocationHandler, ConnectionObserver {
|
public class ConnectionProxyHandler
|
||||||
|
extends AbstractProxyHandler
|
||||||
|
implements InvocationHandler, NonDurableConnectionObserver {
|
||||||
private static final Logger log = LoggerFactory.getLogger( ConnectionProxyHandler.class );
|
private static final Logger log = LoggerFactory.getLogger( ConnectionProxyHandler.class );
|
||||||
|
|
||||||
private LogicalConnectionImplementor logicalConnection;
|
private LogicalConnectionImplementor logicalConnection;
|
||||||
|
@ -112,6 +112,10 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( "isClosed".equals( methodName ) ) {
|
||||||
|
return ! isValid();
|
||||||
|
}
|
||||||
|
|
||||||
errorIfInvalid();
|
errorIfInvalid();
|
||||||
|
|
||||||
// handle the JDBC 4 Wrapper#isWrapperFor and Wrapper#unwrap calls
|
// handle the JDBC 4 Wrapper#isWrapperFor and Wrapper#unwrap calls
|
||||||
|
@ -185,9 +189,7 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postProcessPreparedStatement(Statement statement) throws SQLException {
|
private void postProcessPreparedStatement(Statement statement) throws SQLException {
|
||||||
if ( getStatisticsImplementorOrNull() != null ) {
|
logicalConnection.notifyObserversStatementPrepared();
|
||||||
getStatisticsImplementorOrNull().prepareStatement();
|
|
||||||
}
|
|
||||||
postProcessStatement( statement );
|
postProcessStatement( statement );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,29 +205,25 @@ public class ConnectionProxyHandler extends AbstractProxyHandler implements Invo
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ConnectionObserver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
@Override
|
||||||
public void physicalConnectionObtained(Connection connection) {
|
public void physicalConnectionObtained(Connection connection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void physicalConnectionReleased() {
|
public void physicalConnectionReleased() {
|
||||||
log.info( "logical connection releasing its physical connection");
|
log.info( "logical connection releasing its physical connection");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void logicalConnectionClosed() {
|
public void logicalConnectionClosed() {
|
||||||
log.info( "*** logical connection closed ***" );
|
log.info( "*** logical connection closed ***" );
|
||||||
invalidateHandle();
|
invalidateHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package-protected */
|
@Override
|
||||||
StatisticsImplementor getStatisticsImplementorOrNull() {
|
public void statementPrepared() {
|
||||||
return getLogicalConnection().getStatisticsImplementor();
|
// N/A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,4 +47,9 @@ public interface ConnectionObserver {
|
||||||
* The logical connection was closed.
|
* The logical connection was closed.
|
||||||
*/
|
*/
|
||||||
public void logicalConnectionClosed();
|
public void logicalConnectionClosed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification of a statement being prepared
|
||||||
|
*/
|
||||||
|
public void statementPrepared();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,47 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
* Lesser General Public License, as published by the Free Software Foundation.
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
* for more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with this distribution; if not, write to:
|
* along with this distribution; if not, write to:
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
*/
|
||||||
*/
|
package org.hibernate.engine.jdbc.spi;
|
||||||
package org.hibernate.jdbc;
|
|
||||||
|
import java.sql.Connection;
|
||||||
import java.sql.Connection;
|
|
||||||
|
/**
|
||||||
/**
|
* @author Steve Ebersole
|
||||||
* Interface implemented by JDBC connection wrappers in order to give
|
*/
|
||||||
* access to the underlying wrapped connection.
|
public class ConnectionObserverAdapter implements ConnectionObserver {
|
||||||
*
|
@Override
|
||||||
* @author Steve Ebersole
|
public void physicalConnectionObtained(Connection connection) {
|
||||||
*/
|
}
|
||||||
public interface ConnectionWrapper {
|
|
||||||
/**
|
@Override
|
||||||
* Get a reference to the wrapped connection.
|
public void physicalConnectionReleased() {
|
||||||
*
|
}
|
||||||
* @return The wrapped connection.
|
|
||||||
*/
|
@Override
|
||||||
public Connection getWrappedConnection();
|
public void logicalConnectionClosed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void statementPrepared() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,35 +20,32 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction;
|
package org.hibernate.engine.jdbc.spi;
|
||||||
|
|
||||||
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link TransactionManagerLookup} strategy for Orion
|
* Access to services needed in the context of processing JDBC requests.
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class OrionTransactionManagerLookup extends JNDITransactionManagerLookup {
|
public interface JdbcContext extends Serializable {
|
||||||
|
public SessionFactoryImplementor getSessionFactory();
|
||||||
|
public ConnectionReleaseMode getConnectionReleaseMode();
|
||||||
|
|
||||||
/**
|
public boolean isClosed();
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
protected String getName() {
|
|
||||||
return "java:comp/UserTransaction";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public boolean isFlushModeNever();
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public String getUserTransactionName() {
|
|
||||||
return "java:comp/UserTransaction";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public boolean isFlushBeforeCompletionEnabled();
|
||||||
|
|
||||||
|
public void managedFlush();
|
||||||
|
|
||||||
|
public boolean shouldAutoClose();
|
||||||
|
|
||||||
|
public void managedClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
package org.hibernate.engine.jdbc.spi;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ import java.sql.Statement;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface JdbcResourceRegistry {
|
public interface JdbcResourceRegistry extends Serializable {
|
||||||
/**
|
/**
|
||||||
* Register a JDBC statement.
|
* Register a JDBC statement.
|
||||||
*
|
*
|
||||||
|
|
|
@ -31,7 +31,7 @@ import java.sql.Connection;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface LogicalConnection {
|
public interface LogicalConnection extends Serializable {
|
||||||
/**
|
/**
|
||||||
* Is this logical connection open? Another phraseology sometimes used is: "are we
|
* Is this logical connection open? Another phraseology sometimes used is: "are we
|
||||||
* logically connected"?
|
* logically connected"?
|
||||||
|
@ -55,10 +55,27 @@ public interface LogicalConnection {
|
||||||
* connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
|
* connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
|
||||||
* or has previously been aggressively released.
|
* or has previously been aggressively released.
|
||||||
*
|
*
|
||||||
|
* @todo ?? Move this to {@link LogicalConnectionImplementor} in lieu of {@link #getShareableConnectionProxy} and {@link #getDistinctConnectionProxy} ??
|
||||||
|
*
|
||||||
* @return The current Connection.
|
* @return The current Connection.
|
||||||
*/
|
*/
|
||||||
public Connection getConnection();
|
public Connection getConnection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the shareable connection proxy (see {@link org.hibernate.engine.jdbc.internal.proxy} for details).
|
||||||
|
*
|
||||||
|
* @return The shareable connection proxy.
|
||||||
|
*/
|
||||||
|
public Connection getShareableConnectionProxy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a distinct connection proxy (see {@link org.hibernate.engine.jdbc.internal.proxy} for details). It
|
||||||
|
* is distinct in that it is not shared with others unless the caller explicitly shares it.
|
||||||
|
*
|
||||||
|
* @return The distinct connection proxy.
|
||||||
|
*/
|
||||||
|
public Connection getDistinctConnectionProxy();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release the underlying connection and clean up any other resources associated
|
* Release the underlying connection and clean up any other resources associated
|
||||||
* with this logical connection.
|
* with this logical connection.
|
||||||
|
@ -68,4 +85,6 @@ public interface LogicalConnection {
|
||||||
* @return The physical connection which was being used.
|
* @return The physical connection which was being used.
|
||||||
*/
|
*/
|
||||||
public Connection close();
|
public Connection close();
|
||||||
|
|
||||||
|
public void afterTransaction();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,11 @@
|
||||||
package org.hibernate.engine.jdbc.spi;
|
package org.hibernate.engine.jdbc.spi;
|
||||||
|
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
|
import org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler;
|
||||||
import org.hibernate.stat.StatisticsImplementor;
|
import org.hibernate.stat.StatisticsImplementor;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "internal" contract for LogicalConnection
|
* The "internal" contract for LogicalConnection
|
||||||
*
|
*
|
||||||
|
@ -39,13 +42,6 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
|
||||||
*/
|
*/
|
||||||
public JdbcServices getJdbcServices();
|
public JdbcServices getJdbcServices();
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the statistics implementor.
|
|
||||||
*
|
|
||||||
* @return the statistics implementor
|
|
||||||
*/
|
|
||||||
public StatisticsImplementor getStatisticsImplementor();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the JDBC resource registry associated with this logical connection.
|
* Obtains the JDBC resource registry associated with this logical connection.
|
||||||
*
|
*
|
||||||
|
@ -60,6 +56,13 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
|
||||||
*/
|
*/
|
||||||
public void addObserver(ConnectionObserver observer);
|
public void addObserver(ConnectionObserver observer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an observer
|
||||||
|
*
|
||||||
|
* @param connectionObserver The observer to remove.
|
||||||
|
*/
|
||||||
|
public void removeObserver(ConnectionObserver connectionObserver);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The release mode under which this logical connection is operating.
|
* The release mode under which this logical connection is operating.
|
||||||
*
|
*
|
||||||
|
@ -91,5 +94,26 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
|
||||||
*/
|
*/
|
||||||
public void enableReleases();
|
public void enableReleases();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually disconnect the underlying JDBC Connection. The assumption here
|
||||||
|
* is that the manager will be reconnected at a later point in time.
|
||||||
|
*
|
||||||
|
* @return The connection maintained here at time of disconnect. Null if
|
||||||
|
* there was no connection cached internally.
|
||||||
|
*/
|
||||||
|
public Connection manualDisconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually reconnect the underlying JDBC Connection. Should be called at some point after manualDisconnect().
|
||||||
|
*
|
||||||
|
* @param suppliedConnection For user supplied connection strategy the user needs to hand us the connection
|
||||||
|
* with which to reconnect. It is an error to pass a connection in the other strategies.
|
||||||
|
*/
|
||||||
|
public void manualReconnect(Connection suppliedConnection);
|
||||||
|
|
||||||
|
public boolean isAutoCommit();
|
||||||
|
|
||||||
|
public boolean isReadyForSerialization();
|
||||||
|
|
||||||
|
public void notifyObserversStatementPrepared();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,23 +20,14 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction;
|
package org.hibernate.engine.jdbc.spi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link TransactionManagerLookup} lookup strategy for JBoss AS.
|
* Additional optional contract for connection observers to indicate that they should be released when the physical
|
||||||
|
* connection is released.
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public final class JBossTransactionManagerLookup extends JNDITransactionManagerLookup {
|
public interface NonDurableConnectionObserver extends ConnectionObserver {
|
||||||
|
|
||||||
protected String getName() {
|
|
||||||
return "java:/TransactionManager";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserTransactionName() {
|
|
||||||
return "UserTransaction";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.jdbc.spi;
|
package org.hibernate.engine.jdbc.spi;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.SQLWarning;
|
import java.sql.SQLWarning;
|
||||||
|
@ -41,7 +42,7 @@ import org.hibernate.util.StringHelper;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SQLExceptionHelper {
|
public class SQLExceptionHelper implements Serializable {
|
||||||
private static final Logger log = LoggerFactory.getLogger( SQLExceptionHelper.class );
|
private static final Logger log = LoggerFactory.getLogger( SQLExceptionHelper.class );
|
||||||
|
|
||||||
public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";
|
public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";
|
||||||
|
|
|
@ -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 );
|
session );
|
||||||
String sql = queryParameters.getFilteredSQL();
|
String sql = queryParameters.getFilteredSQL();
|
||||||
|
|
||||||
ps = session.getJDBCContext().getConnectionManager().prepareStatement( sql, false );
|
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int col = 1;
|
int col = 1;
|
||||||
|
|
|
@ -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
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.transaction;
|
package org.hibernate.engine.transaction.internal;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO : javadoc
|
* Indicates an attempt to register a null synchronization. Basically a glorified {@link NullPointerException}
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,7 +21,9 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.transaction;
|
package org.hibernate.engine.transaction.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.transaction.spi.SynchronizationRegistry;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import javax.transaction.Synchronization;
|
import javax.transaction.Synchronization;
|
||||||
|
@ -29,25 +31,17 @@ import javax.transaction.Synchronization;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages a registry of {@link Synchronization Synchronizations}.
|
* Manages a registry of {@link Synchronization Synchronizations}.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SynchronizationRegistry {
|
public class SynchronizationRegistryImpl implements SynchronizationRegistry {
|
||||||
private static final Logger log = LoggerFactory.getLogger( SynchronizationRegistry.class );
|
private static final Logger log = LoggerFactory.getLogger( SynchronizationRegistryImpl.class );
|
||||||
|
|
||||||
private LinkedHashSet<Synchronization> synchronizations;
|
private LinkedHashSet<Synchronization> synchronizations;
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Register a user {@link Synchronization} callback for this transaction.
|
|
||||||
*
|
|
||||||
* @param synchronization The synchronization callback to register.
|
|
||||||
*
|
|
||||||
* @throws HibernateException
|
|
||||||
*/
|
|
||||||
public void registerSynchronization(Synchronization synchronization) {
|
public void registerSynchronization(Synchronization synchronization) {
|
||||||
if ( synchronization == null ) {
|
if ( synchronization == null ) {
|
||||||
throw new NullSynchronizationException();
|
throw new NullSynchronizationException();
|
||||||
|
@ -63,10 +57,7 @@ public class SynchronizationRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Delegate {@link Synchronization#beforeCompletion} calls to {@link #registerSynchronization registered}
|
|
||||||
* {@link Synchronization Synchronizations}
|
|
||||||
*/
|
|
||||||
public void notifySynchronizationsBeforeTransactionCompletion() {
|
public void notifySynchronizationsBeforeTransactionCompletion() {
|
||||||
if ( synchronizations != null ) {
|
if ( synchronizations != null ) {
|
||||||
for ( Synchronization synchronization : synchronizations ) {
|
for ( Synchronization synchronization : synchronizations ) {
|
||||||
|
@ -80,12 +71,7 @@ public class SynchronizationRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Delegate {@link Synchronization#afterCompletion} calls to {@link #registerSynchronization registered}
|
|
||||||
* {@link Synchronization Synchronizations}
|
|
||||||
*
|
|
||||||
* @param status The transaction status (if known) per {@link javax.transaction.Status}
|
|
||||||
*/
|
|
||||||
public void notifySynchronizationsAfterTransactionCompletion(int status) {
|
public void notifySynchronizationsAfterTransactionCompletion(int status) {
|
||||||
if ( synchronizations != null ) {
|
if ( synchronizations != null ) {
|
||||||
for ( Synchronization synchronization : synchronizations ) {
|
for ( Synchronization synchronization : synchronizations ) {
|
||||||
|
@ -98,4 +84,14 @@ public class SynchronizationRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Package-protected access to clear registered synchronizations.
|
||||||
|
*/
|
||||||
|
void clearSynchronizations() {
|
||||||
|
if ( synchronizations != null ) {
|
||||||
|
synchronizations.clear();
|
||||||
|
synchronizations = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,60 +20,64 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction;
|
package org.hibernate.engine.transaction.internal.jta;
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.TransactionException;
|
import org.hibernate.TransactionException;
|
||||||
import org.hibernate.engine.jdbc.spi.JDBCContext;
|
import org.hibernate.engine.transaction.spi.JoinStatus;
|
||||||
import org.hibernate.util.JTAHelper;
|
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionFactory;
|
||||||
|
|
||||||
import javax.transaction.SystemException;
|
import javax.transaction.SystemException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for {@link CMTTransaction} instances.
|
* Factory for Container Managed Transaction (CMT) based transaction facades.
|
||||||
*
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class CMTTransactionFactory implements TransactionFactory {
|
public class CMTTransactionFactory implements TransactionFactory<CMTTransaction> {
|
||||||
|
@Override
|
||||||
|
public CMTTransaction createTransaction(TransactionCoordinator transactionCoordinator) {
|
||||||
|
return new CMTTransaction( transactionCoordinator );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canBeDriver() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ConnectionReleaseMode getDefaultReleaseMode() {
|
public ConnectionReleaseMode getDefaultReleaseMode() {
|
||||||
return ConnectionReleaseMode.AFTER_STATEMENT;
|
return ConnectionReleaseMode.AFTER_STATEMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configure(Properties props) throws HibernateException {}
|
@Override
|
||||||
|
public boolean compatibleWithJtaSynchronization() {
|
||||||
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
|
|
||||||
throws HibernateException {
|
|
||||||
return new CMTTransaction(jdbcContext, transactionContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTransactionManagerRequired() {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean areCallbacksLocalToHibernateTransactions() {
|
@Override
|
||||||
return false;
|
public boolean isJoinableJtaTransaction(TransactionCoordinator transactionCoordinator, CMTTransaction transaction) {
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTransactionInProgress(
|
|
||||||
JDBCContext jdbcContext,
|
|
||||||
Context transactionContext,
|
|
||||||
Transaction transaction) {
|
|
||||||
try {
|
try {
|
||||||
return JTAHelper.isTransactionInProgress(
|
final int status = transactionCoordinator
|
||||||
transactionContext.getFactory().getTransactionManager().getTransaction()
|
.getTransactionContext()
|
||||||
);
|
.getTransactionEnvironment()
|
||||||
|
.getJtaPlatform()
|
||||||
|
.retrieveTransactionManager()
|
||||||
|
.getStatus();
|
||||||
|
return JtaStatusHelper.isActive( status );
|
||||||
}
|
}
|
||||||
catch( SystemException se ) {
|
catch( SystemException se ) {
|
||||||
throw new TransactionException( "Unable to check transaction status", se );
|
throw new TransactionException( "Unable to check transaction status", se );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JoinStatus getJoinStatus(TransactionCoordinator transactionCoordinator, CMTTransaction transaction) {
|
||||||
|
return null; // todo : implement method body
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.internal.util.jta;
|
package org.hibernate.engine.transaction.internal.jta;
|
||||||
|
|
||||||
import javax.transaction.Status;
|
import javax.transaction.Status;
|
||||||
import javax.transaction.SystemException;
|
import javax.transaction.SystemException;
|
||||||
|
@ -31,7 +31,7 @@ import javax.transaction.UserTransaction;
|
||||||
import org.hibernate.TransactionException;
|
import org.hibernate.TransactionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility for dealing with JTA statses.
|
* Utility for dealing with JTA statuses.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@ -49,7 +49,7 @@ public class JtaStatusHelper {
|
||||||
try {
|
try {
|
||||||
final int status = userTransaction.getStatus();
|
final int status = userTransaction.getStatus();
|
||||||
if ( status == Status.STATUS_UNKNOWN ) {
|
if ( status == Status.STATUS_UNKNOWN ) {
|
||||||
throw new TransactionException( "UserTransaction reported transaction status as unknwon" );
|
throw new TransactionException( "UserTransaction reported transaction status as unknown" );
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ public class JtaStatusHelper {
|
||||||
*
|
*
|
||||||
* @param userTransaction The {@link UserTransaction} whose status is to be checked
|
* @param userTransaction The {@link UserTransaction} whose status is to be checked
|
||||||
*
|
*
|
||||||
* @return True if the transactiion is active; false otherwise.
|
* @return True if the transaction is active; false otherwise.
|
||||||
*/
|
*/
|
||||||
public static boolean isActive(UserTransaction userTransaction) {
|
public static boolean isActive(UserTransaction userTransaction) {
|
||||||
final int status = getStatus( userTransaction );
|
final int status = getStatus( userTransaction );
|
||||||
|
@ -109,7 +109,7 @@ public class JtaStatusHelper {
|
||||||
*
|
*
|
||||||
* @param transactionManager The {@link TransactionManager} whose status is to be checked
|
* @param transactionManager The {@link TransactionManager} whose status is to be checked
|
||||||
*
|
*
|
||||||
* @return True if the transactiion is active; false otherwise.
|
* @return True if the transaction is active; false otherwise.
|
||||||
*/
|
*/
|
||||||
public static boolean isActive(TransactionManager transactionManager) {
|
public static boolean isActive(TransactionManager transactionManager) {
|
||||||
return isActive( getStatus( transactionManager ) );
|
return isActive( getStatus( transactionManager ) );
|
||||||
|
@ -133,7 +133,7 @@ public class JtaStatusHelper {
|
||||||
*
|
*
|
||||||
* @param userTransaction The {@link UserTransaction} whose status is to be checked
|
* @param userTransaction The {@link UserTransaction} whose status is to be checked
|
||||||
*
|
*
|
||||||
* @return True if the transactiion indicates roll back; false otherwise.
|
* @return True if the transaction indicates roll back; false otherwise.
|
||||||
*/
|
*/
|
||||||
public static boolean isRollback(UserTransaction userTransaction) {
|
public static boolean isRollback(UserTransaction userTransaction) {
|
||||||
return isRollback( getStatus( userTransaction ) );
|
return isRollback( getStatus( userTransaction ) );
|
||||||
|
@ -144,7 +144,7 @@ public class JtaStatusHelper {
|
||||||
*
|
*
|
||||||
* @param transactionManager The {@link TransactionManager} whose status is to be checked
|
* @param transactionManager The {@link TransactionManager} whose status is to be checked
|
||||||
*
|
*
|
||||||
* @return True if the transactiion indicates roll back; false otherwise.
|
* @return True if the transaction indicates roll back; false otherwise.
|
||||||
*/
|
*/
|
||||||
public static boolean isRollback(TransactionManager transactionManager) {
|
public static boolean isRollback(TransactionManager transactionManager) {
|
||||||
return isRollback( getStatus( transactionManager ) );
|
return isRollback( getStatus( transactionManager ) );
|
||||||
|
@ -158,9 +158,7 @@ public class JtaStatusHelper {
|
||||||
* @return True if the code indicates a roll back; false otherwise.
|
* @return True if the code indicates a roll back; false otherwise.
|
||||||
*/
|
*/
|
||||||
public static boolean isCommitted(int status) {
|
public static boolean isCommitted(int status) {
|
||||||
return status == Status.STATUS_MARKED_ROLLBACK ||
|
return status == Status.STATUS_COMMITTED;
|
||||||
status == Status.STATUS_ROLLING_BACK ||
|
|
||||||
status == Status.STATUS_ROLLEDBACK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -168,7 +166,7 @@ public class JtaStatusHelper {
|
||||||
*
|
*
|
||||||
* @param userTransaction The {@link UserTransaction} whose status is to be checked
|
* @param userTransaction The {@link UserTransaction} whose status is to be checked
|
||||||
*
|
*
|
||||||
* @return True if the transactiion indicates commit; false otherwise.
|
* @return True if the transaction indicates commit; false otherwise.
|
||||||
*/
|
*/
|
||||||
public static boolean isCommitted(UserTransaction userTransaction) {
|
public static boolean isCommitted(UserTransaction userTransaction) {
|
||||||
return isCommitted( getStatus( userTransaction ) );
|
return isCommitted( getStatus( userTransaction ) );
|
||||||
|
@ -179,7 +177,7 @@ public class JtaStatusHelper {
|
||||||
*
|
*
|
||||||
* @param transactionManager The {@link TransactionManager} whose status is to be checked
|
* @param transactionManager The {@link TransactionManager} whose status is to be checked
|
||||||
*
|
*
|
||||||
* @return True if the transactiion indicates commit; false otherwise.
|
* @return True if the transaction indicates commit; false otherwise.
|
||||||
*/
|
*/
|
||||||
public static boolean isCommitted(TransactionManager transactionManager) {
|
public static boolean isCommitted(TransactionManager transactionManager) {
|
||||||
return isCommitted( getStatus( transactionManager ) );
|
return isCommitted( getStatus( transactionManager ) );
|
||||||
|
@ -192,6 +190,7 @@ public class JtaStatusHelper {
|
||||||
*
|
*
|
||||||
* @return True if the code indicates a roll back; false otherwise.
|
* @return True if the code indicates a roll back; false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
public static boolean isMarkedForRollback(int status) {
|
public static boolean isMarkedForRollback(int status) {
|
||||||
return status == Status.STATUS_MARKED_ROLLBACK;
|
return status == Status.STATUS_MARKED_ROLLBACK;
|
||||||
}
|
}
|
|
@ -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
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,15 +21,16 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction.synchronization;
|
package org.hibernate.engine.transaction.spi;
|
||||||
|
|
||||||
import org.hibernate.transaction.TransactionFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO : javadoc
|
* See the JPA notion of joining a transaction for details.
|
||||||
*
|
*
|
||||||
|
* @author Emmanuel Bernard
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface AfterCompletionAction {
|
public enum JoinStatus {
|
||||||
public void doAction(TransactionFactory.Context ctx, int status);
|
NOT_JOINED,
|
||||||
|
MARKED_FOR_JOINED,
|
||||||
|
JOINED
|
||||||
}
|
}
|
|
@ -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
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,26 +21,26 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction.synchronization;
|
package org.hibernate.engine.transaction.synchronization.internal;
|
||||||
|
|
||||||
import javax.transaction.Synchronization;
|
|
||||||
|
|
||||||
|
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.transaction.Synchronization;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link Synchronization} implementation Hibernate registers with the JTA {@link javax.transaction.Transaction}
|
* The JTA {@link javax.transaction.Synchronization} Hibernate registers when needed for JTA callbacks
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class HibernateSynchronizationImpl implements Synchronization {
|
public class RegisteredSynchronization implements Synchronization {
|
||||||
private static final Logger log = LoggerFactory.getLogger( HibernateSynchronizationImpl.class );
|
private static final Logger log = LoggerFactory.getLogger( RegisteredSynchronization.class );
|
||||||
|
|
||||||
private final CallbackCoordinator coordinator;
|
private final SynchronizationCallbackCoordinator synchronizationCallbackCoordinator;
|
||||||
|
|
||||||
public HibernateSynchronizationImpl(CallbackCoordinator coordinator) {
|
public RegisteredSynchronization(SynchronizationCallbackCoordinator synchronizationCallbackCoordinator) {
|
||||||
this.coordinator = coordinator;
|
this.synchronizationCallbackCoordinator = synchronizationCallbackCoordinator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +48,7 @@ public class HibernateSynchronizationImpl implements Synchronization {
|
||||||
*/
|
*/
|
||||||
public void beforeCompletion() {
|
public void beforeCompletion() {
|
||||||
log.trace( "JTA sync : beforeCompletion()" );
|
log.trace( "JTA sync : beforeCompletion()" );
|
||||||
coordinator.beforeCompletion();
|
synchronizationCallbackCoordinator.beforeCompletion();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,6 +56,6 @@ public class HibernateSynchronizationImpl implements Synchronization {
|
||||||
*/
|
*/
|
||||||
public void afterCompletion(int status) {
|
public void afterCompletion(int status) {
|
||||||
log.trace( "JTA sync : afterCompletion({})", status );
|
log.trace( "JTA sync : afterCompletion({})", status );
|
||||||
coordinator.afterCompletion( status );
|
synchronizationCallbackCoordinator.afterCompletion( status );
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,75 +21,57 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction.synchronization;
|
package org.hibernate.engine.transaction.synchronization.internal;
|
||||||
|
|
||||||
import javax.transaction.Status;
|
|
||||||
import javax.transaction.SystemException;
|
|
||||||
import javax.transaction.Transaction;
|
|
||||||
|
|
||||||
|
import org.hibernate.TransactionException;
|
||||||
|
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionContext;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||||
|
import org.hibernate.engine.transaction.synchronization.spi.AfterCompletionAction;
|
||||||
|
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
|
||||||
|
import org.hibernate.engine.transaction.synchronization.spi.ExceptionMapper;
|
||||||
|
import org.hibernate.engine.transaction.synchronization.spi.ManagedFlushChecker;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.TransactionException;
|
import javax.transaction.SystemException;
|
||||||
import org.hibernate.engine.jdbc.spi.JDBCContext;
|
|
||||||
import org.hibernate.transaction.TransactionFactory;
|
|
||||||
import org.hibernate.util.JTAHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages callbacks from the {@link javax.transaction.Synchronization} registered by Hibernate.
|
* Manages callbacks from the {@link javax.transaction.Synchronization} registered by Hibernate.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class CallbackCoordinator {
|
public class SynchronizationCallbackCoordinatorImpl implements SynchronizationCallbackCoordinator {
|
||||||
private static final Logger log = LoggerFactory.getLogger( CallbackCoordinator.class );
|
private static final Logger log = LoggerFactory.getLogger( SynchronizationCallbackCoordinatorImpl.class );
|
||||||
|
|
||||||
private final TransactionFactory.Context ctx;
|
private final TransactionCoordinator transactionCoordinator;
|
||||||
private JDBCContext jdbcContext;
|
|
||||||
private final Transaction jtaTransaction;
|
|
||||||
private final org.hibernate.Transaction hibernateTransaction;
|
|
||||||
|
|
||||||
private BeforeCompletionManagedFlushChecker beforeCompletionManagedFlushChecker;
|
private ManagedFlushChecker managedFlushChecker;
|
||||||
private AfterCompletionAction afterCompletionAction;
|
private AfterCompletionAction afterCompletionAction;
|
||||||
private ExceptionMapper exceptionMapper;
|
private ExceptionMapper exceptionMapper;
|
||||||
|
|
||||||
public CallbackCoordinator(
|
public SynchronizationCallbackCoordinatorImpl(TransactionCoordinator transactionCoordinator) {
|
||||||
TransactionFactory.Context ctx,
|
this.transactionCoordinator = transactionCoordinator;
|
||||||
JDBCContext jdbcContext,
|
|
||||||
Transaction jtaTransaction,
|
|
||||||
org.hibernate.Transaction hibernateTransaction) {
|
|
||||||
this.ctx = ctx;
|
|
||||||
this.jdbcContext = jdbcContext;
|
|
||||||
this.jtaTransaction = jtaTransaction;
|
|
||||||
this.hibernateTransaction = hibernateTransaction;
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
beforeCompletionManagedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER;
|
managedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER;
|
||||||
exceptionMapper = STANDARD_EXCEPTION_MAPPER;
|
exceptionMapper = STANDARD_EXCEPTION_MAPPER;
|
||||||
afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION;
|
afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeforeCompletionManagedFlushChecker getBeforeCompletionManagedFlushChecker() {
|
@Override
|
||||||
return beforeCompletionManagedFlushChecker;
|
public void setManagedFlushChecker(ManagedFlushChecker managedFlushChecker) {
|
||||||
}
|
this.managedFlushChecker = managedFlushChecker;
|
||||||
|
|
||||||
public void setBeforeCompletionManagedFlushChecker(BeforeCompletionManagedFlushChecker beforeCompletionManagedFlushChecker) {
|
|
||||||
this.beforeCompletionManagedFlushChecker = beforeCompletionManagedFlushChecker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExceptionMapper getExceptionMapper() {
|
|
||||||
return exceptionMapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setExceptionMapper(ExceptionMapper exceptionMapper) {
|
public void setExceptionMapper(ExceptionMapper exceptionMapper) {
|
||||||
this.exceptionMapper = exceptionMapper;
|
this.exceptionMapper = exceptionMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AfterCompletionAction getAfterCompletionAction() {
|
@Override
|
||||||
return afterCompletionAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAfterCompletionAction(AfterCompletionAction afterCompletionAction) {
|
public void setAfterCompletionAction(AfterCompletionAction afterCompletionAction) {
|
||||||
this.afterCompletionAction = afterCompletionAction;
|
this.afterCompletionAction = afterCompletionAction;
|
||||||
}
|
}
|
||||||
|
@ -102,7 +84,12 @@ public class CallbackCoordinator {
|
||||||
|
|
||||||
boolean flush;
|
boolean flush;
|
||||||
try {
|
try {
|
||||||
flush = beforeCompletionManagedFlushChecker.shouldDoManagedFlush( ctx, jtaTransaction );
|
final int status = transactionCoordinator
|
||||||
|
.getTransactionContext()
|
||||||
|
.getTransactionEnvironment()
|
||||||
|
.getJtaPlatform()
|
||||||
|
.getCurrentStatus();
|
||||||
|
flush = managedFlushChecker.shouldDoManagedFlush( transactionCoordinator, status );
|
||||||
}
|
}
|
||||||
catch ( SystemException se ) {
|
catch ( SystemException se ) {
|
||||||
setRollbackOnly();
|
setRollbackOnly();
|
||||||
|
@ -112,7 +99,7 @@ public class CallbackCoordinator {
|
||||||
try {
|
try {
|
||||||
if ( flush ) {
|
if ( flush ) {
|
||||||
log.trace( "automatically flushing session" );
|
log.trace( "automatically flushing session" );
|
||||||
ctx.managedFlush();
|
transactionCoordinator.getTransactionContext().managedFlush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( RuntimeException re ) {
|
catch ( RuntimeException re ) {
|
||||||
|
@ -120,48 +107,41 @@ public class CallbackCoordinator {
|
||||||
throw exceptionMapper.mapManagedFlushFailure( "error during managed flush", re );
|
throw exceptionMapper.mapManagedFlushFailure( "error during managed flush", re );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
jdbcContext.beforeTransactionCompletion( hibernateTransaction );
|
transactionCoordinator.sendBeforeTransactionCompletionNotifications( null );
|
||||||
|
transactionCoordinator.getTransactionContext().beforeTransactionCompletion( null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setRollbackOnly() {
|
private void setRollbackOnly() {
|
||||||
try {
|
transactionCoordinator.setRollbackOnly();
|
||||||
jtaTransaction.setRollbackOnly();
|
|
||||||
}
|
|
||||||
catch ( SystemException se ) {
|
|
||||||
// best effort
|
|
||||||
log.error( "could not set transaction to rollback only", se );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterCompletion(int status) {
|
public void afterCompletion(int status) {
|
||||||
log.trace( "transaction after completion callback [status={}]", status );
|
log.trace( "transaction after completion callback [status={}]", status );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
afterCompletionAction.doAction( ctx, status );
|
afterCompletionAction.doAction( transactionCoordinator, status );
|
||||||
|
transactionCoordinator.afterTransaction( null, status );
|
||||||
final boolean wasSuccessful = ( status == Status.STATUS_COMMITTED );
|
|
||||||
jdbcContext.afterTransactionCompletion( wasSuccessful, hibernateTransaction );
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
reset();
|
reset();
|
||||||
jdbcContext.cleanUpJtaSynchronizationCallbackCoordinator();
|
if ( transactionContext().shouldAutoClose() && ! transactionContext().isClosed() ) {
|
||||||
if ( ctx.shouldAutoClose() && !ctx.isClosed() ) {
|
|
||||||
log.trace( "automatically closing session" );
|
log.trace( "automatically closing session" );
|
||||||
ctx.managedClose();
|
transactionContext().managedClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final BeforeCompletionManagedFlushChecker STANDARD_MANAGED_FLUSH_CHECKER = new BeforeCompletionManagedFlushChecker() {
|
private TransactionContext transactionContext() {
|
||||||
public boolean shouldDoManagedFlush(TransactionFactory.Context ctx, Transaction jtaTransaction)
|
return transactionCoordinator.getTransactionContext();
|
||||||
throws SystemException {
|
}
|
||||||
return !ctx.isClosed() &&
|
|
||||||
!ctx.isFlushModeNever() &&
|
private static final ManagedFlushChecker STANDARD_MANAGED_FLUSH_CHECKER = new ManagedFlushChecker() {
|
||||||
ctx.isFlushBeforeCompletionEnabled() &&
|
@Override
|
||||||
!JTAHelper.isRollback( jtaTransaction.getStatus() );
|
public boolean shouldDoManagedFlush(TransactionCoordinator coordinator, int jtaStatus) {
|
||||||
//actually, this last test is probably unnecessary, since
|
return coordinator.getTransactionContext().isFlushModeNever() &&
|
||||||
//beforeCompletion() doesn't get called during rollback
|
coordinator.getTransactionContext().isFlushBeforeCompletionEnabled() &&
|
||||||
|
!JtaStatusHelper.isRollback( jtaStatus );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,7 +158,8 @@ public class CallbackCoordinator {
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final AfterCompletionAction STANDARD_AFTER_COMPLETION_ACTION = new AfterCompletionAction() {
|
private static final AfterCompletionAction STANDARD_AFTER_COMPLETION_ACTION = new AfterCompletionAction() {
|
||||||
public void doAction(TransactionFactory.Context ctx, int status) {
|
@Override
|
||||||
|
public void doAction(TransactionCoordinator transactionCoordinator, int status) {
|
||||||
// nothing to do by default.
|
// nothing to do by default.
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -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
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,18 +21,20 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction.synchronization;
|
package org.hibernate.engine.transaction.synchronization.spi;
|
||||||
|
|
||||||
import javax.transaction.SystemException;
|
import javax.transaction.SystemException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO : javadoc
|
* A pluggable strategy for defining how the {@link javax.transaction.Synchronization} registered by Hibernate handles
|
||||||
|
* exceptions.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface ExceptionMapper {
|
public interface ExceptionMapper extends Serializable {
|
||||||
/**
|
/**
|
||||||
* Map a JTA {@link SystemException} to the appropriate runtime-based exception.
|
* Map a JTA {@link javax.transaction.SystemException} to the appropriate runtime-based exception.
|
||||||
*
|
*
|
||||||
* @param message The message to use for the returned exception
|
* @param message The message to use for the returned exception
|
||||||
* @param systemException The causal exception
|
* @param systemException The causal exception
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,31 +21,27 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.transaction.synchronization;
|
package org.hibernate.engine.transaction.synchronization.spi;
|
||||||
|
|
||||||
import javax.transaction.SystemException;
|
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||||
import javax.transaction.Transaction;
|
|
||||||
|
|
||||||
import org.hibernate.transaction.TransactionFactory;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract for checking whether to perform a managed flush in a
|
* A pluggable strategy for defining how the {@link javax.transaction.Synchronization} registered by Hibernate determines
|
||||||
* {@link javax.transaction.Synchronization#beforeCompletion()} callback
|
* whether to perform a managed flush. An exceptions from either this delegate or the subsequent flush are routed
|
||||||
|
* through the sister strategy {@link ExceptionMapper}.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface BeforeCompletionManagedFlushChecker {
|
public interface ManagedFlushChecker extends Serializable {
|
||||||
/**
|
/**
|
||||||
* Check whether we should perform the managed flush
|
* Check whether we should perform the managed flush
|
||||||
*
|
*
|
||||||
* @param ctx The Hibernate "transaction context"
|
* @param coordinator The transaction coordinator
|
||||||
* @param jtaTransaction The JTA transaction
|
* @param jtaStatus The status of the current JTA transaction.
|
||||||
*
|
*
|
||||||
* @return True to indicate to perform the managed flush; false otherwise.
|
* @return True to indicate to perform the managed flush; false otherwise.
|
||||||
*
|
|
||||||
* @throws SystemException Can be thrown while accessing the JTA transaction; will result in transaction being
|
|
||||||
* marked for rollback (best effort).
|
|
||||||
*/
|
*/
|
||||||
public boolean shouldDoManagedFlush(TransactionFactory.Context ctx, Transaction jtaTransaction)
|
public boolean shouldDoManagedFlush(TransactionCoordinator coordinator, int jtaStatus);
|
||||||
throws SystemException;
|
|
||||||
}
|
}
|
|
@ -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");
|
log.trace("executing flush");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
session.getJDBCContext().getConnectionManager().flushBeginning();
|
session.getTransactionCoordinator().getJdbcCoordinator().flushBeginning();
|
||||||
// we need to lock the collection caches before
|
// we need to lock the collection caches before
|
||||||
// executing entity inserts/updates in order to
|
// executing entity inserts/updates in order to
|
||||||
// account for bidi associations
|
// account for bidi associations
|
||||||
|
@ -325,7 +325,7 @@ public abstract class AbstractFlushingEventListener implements Serializable {
|
||||||
throw he;
|
throw he;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
session.getJDBCContext().getConnectionManager().flushEnding();
|
session.getTransactionCoordinator().getJdbcCoordinator().flushEnding();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,7 @@ public abstract class AbstractSaveEventListener extends AbstractReassociateEvent
|
||||||
|
|
||||||
Serializable id = key == null ? null : key.getIdentifier();
|
Serializable id = key == null ? null : key.getIdentifier();
|
||||||
|
|
||||||
boolean inTxn = source.getJDBCContext().isTransactionInProgress();
|
boolean inTxn = source.getTransactionCoordinator().isTransactionInProgress();
|
||||||
boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
|
boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
|
||||||
|
|
||||||
// Put a placeholder in entries, so we don't recurse back and try to save() the
|
// Put a placeholder in entries, so we don't recurse back and try to save() the
|
||||||
|
|
|
@ -26,6 +26,7 @@ package org.hibernate.exception;
|
||||||
|
|
||||||
import org.hibernate.JDBCException;
|
import org.hibernate.JDBCException;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,9 +43,9 @@ import java.sql.SQLException;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
* @see SQLExceptionConverterFactory
|
* @see SQLExceptionConverterFactory
|
||||||
*/
|
*/
|
||||||
public interface SQLExceptionConverter {
|
public interface SQLExceptionConverter extends Serializable {
|
||||||
/**
|
/**
|
||||||
* Convert the given SQLException into Hibernate's JDBCException hierarchy.
|
* Convert the given SQLException into the Hibernate {@link JDBCException} hierarchy.
|
||||||
*
|
*
|
||||||
* @param sqlException The SQLException to be converted.
|
* @param sqlException The SQLException to be converted.
|
||||||
* @param message An optional error message.
|
* @param message An optional error message.
|
||||||
|
|
|
@ -23,35 +23,33 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.hql.ast.exec;
|
package org.hibernate.hql.ast.exec;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import antlr.RecognitionException;
|
||||||
import java.sql.Connection;
|
import antlr.collections.AST;
|
||||||
import java.sql.SQLWarning;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.action.BulkOperationCleanupAction;
|
import org.hibernate.action.BulkOperationCleanupAction;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.SessionImplementor;
|
import org.hibernate.engine.SessionImplementor;
|
||||||
import org.hibernate.engine.transaction.Isolater;
|
|
||||||
import org.hibernate.engine.transaction.IsolatedWork;
|
|
||||||
import org.hibernate.event.EventSource;
|
import org.hibernate.event.EventSource;
|
||||||
import org.hibernate.hql.ast.HqlSqlWalker;
|
import org.hibernate.hql.ast.HqlSqlWalker;
|
||||||
import org.hibernate.hql.ast.SqlGenerator;
|
import org.hibernate.hql.ast.SqlGenerator;
|
||||||
|
import org.hibernate.jdbc.Work;
|
||||||
import org.hibernate.persister.entity.Queryable;
|
import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.sql.InsertSelect;
|
import org.hibernate.sql.InsertSelect;
|
||||||
import org.hibernate.sql.Select;
|
import org.hibernate.sql.Select;
|
||||||
import org.hibernate.sql.SelectFragment;
|
import org.hibernate.sql.SelectFragment;
|
||||||
import org.hibernate.util.JDBCExceptionReporter;
|
import org.hibernate.util.JDBCExceptionReporter;
|
||||||
import org.hibernate.util.StringHelper;
|
import org.hibernate.util.StringHelper;
|
||||||
|
|
||||||
import antlr.RecognitionException;
|
|
||||||
import antlr.collections.AST;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLWarning;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of AbstractStatementExecutor.
|
* Implementation of AbstractStatementExecutor.
|
||||||
*
|
*
|
||||||
|
@ -139,42 +137,55 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
|
||||||
" from " + persister.getTemporaryIdTableName();
|
" from " + persister.getTemporaryIdTableName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TemporaryTableCreationWork implements Work {
|
||||||
|
private final Queryable persister;
|
||||||
|
|
||||||
|
private TemporaryTableCreationWork(Queryable persister) {
|
||||||
|
this.persister = persister;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Connection connection) {
|
||||||
|
try {
|
||||||
|
Statement statement = connection.createStatement();
|
||||||
|
try {
|
||||||
|
statement.executeUpdate( persister.getTemporaryIdTableDDL() );
|
||||||
|
JDBCExceptionReporter.handleAndClearWarnings( statement, CREATION_WARNING_HANDLER );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
statement.close();
|
||||||
|
}
|
||||||
|
catch( Throwable ignore ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( Exception e ) {
|
||||||
|
LOG.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
protected void createTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
|
protected void createTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
|
||||||
// Don't really know all the codes required to adequately decipher returned jdbc exceptions here.
|
// Don't really know all the codes required to adequately decipher returned jdbc exceptions here.
|
||||||
// simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
|
// simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
|
||||||
IsolatedWork work = new IsolatedWork() {
|
TemporaryTableCreationWork work = new TemporaryTableCreationWork( persister );
|
||||||
public void doWork(Connection connection) throws HibernateException {
|
|
||||||
try {
|
|
||||||
Statement statement = connection.createStatement();
|
|
||||||
try {
|
|
||||||
statement.executeUpdate( persister.getTemporaryIdTableDDL() );
|
|
||||||
JDBCExceptionReporter.handleAndClearWarnings( statement, CREATION_WARNING_HANDLER );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
try {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
catch( Throwable ignore ) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch( Exception e ) {
|
|
||||||
log.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if ( shouldIsolateTemporaryTableDDL() ) {
|
if ( shouldIsolateTemporaryTableDDL() ) {
|
||||||
if ( getFactory().getSettings().isDataDefinitionInTransactionSupported() ) {
|
session.getTransactionCoordinator()
|
||||||
Isolater.doIsolatedWork( work, session );
|
.getTransaction()
|
||||||
}
|
.createIsolationDelegate()
|
||||||
else {
|
.delegateWork( work, getFactory().getSettings().isDataDefinitionInTransactionSupported() );
|
||||||
Isolater.doNonTransactedWork( work, session );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
work.doWork( session.getJDBCContext().getConnectionManager().getConnection() );
|
final Connection connection = session.getTransactionCoordinator()
|
||||||
session.getJDBCContext().getConnectionManager().afterStatement();
|
.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getShareableConnectionProxy();
|
||||||
|
work.execute( connection );
|
||||||
|
session.getTransactionCoordinator()
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.afterStatementExecution();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,53 +205,67 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
|
private static class TemporaryTableDropWork implements Work {
|
||||||
if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) {
|
private final Queryable persister;
|
||||||
IsolatedWork work = new IsolatedWork() {
|
private final SessionImplementor session;
|
||||||
public void doWork(Connection connection) throws HibernateException {
|
|
||||||
final String command = session.getFactory().getDialect().getDropTemporaryTableString()
|
|
||||||
+ ' ' + persister.getTemporaryIdTableName();
|
|
||||||
try {
|
|
||||||
Statement statement = connection.createStatement();
|
|
||||||
try {
|
|
||||||
statement = connection.createStatement();
|
|
||||||
statement.executeUpdate( command );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
try {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
catch( Throwable ignore ) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch( Exception e ) {
|
|
||||||
log.warn( "unable to drop temporary id table after use [" + e.getMessage() + "]" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( shouldIsolateTemporaryTableDDL() ) {
|
private TemporaryTableDropWork(Queryable persister, SessionImplementor session) {
|
||||||
if ( getFactory().getSettings().isDataDefinitionInTransactionSupported() ) {
|
this.persister = persister;
|
||||||
Isolater.doIsolatedWork( work, session );
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Connection connection) {
|
||||||
|
final String command = session.getFactory().getDialect().getDropTemporaryTableString()
|
||||||
|
+ ' ' + persister.getTemporaryIdTableName();
|
||||||
|
try {
|
||||||
|
Statement statement = connection.createStatement();
|
||||||
|
try {
|
||||||
|
statement = connection.createStatement();
|
||||||
|
statement.executeUpdate( command );
|
||||||
}
|
}
|
||||||
else {
|
finally {
|
||||||
Isolater.doNonTransactedWork( work, session );
|
try {
|
||||||
|
statement.close();
|
||||||
|
}
|
||||||
|
catch( Throwable ignore ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch( Exception e ) {
|
||||||
|
LOG.warn( "unable to drop temporary id table after use [" + e.getMessage() + "]" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
|
||||||
|
if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) {
|
||||||
|
TemporaryTableDropWork work = new TemporaryTableDropWork( persister, session );
|
||||||
|
if ( shouldIsolateTemporaryTableDDL() ) {
|
||||||
|
session.getTransactionCoordinator()
|
||||||
|
.getTransaction()
|
||||||
|
.createIsolationDelegate()
|
||||||
|
.delegateWork( work, getFactory().getSettings().isDataDefinitionInTransactionSupported() );
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
work.doWork( session.getJDBCContext().getConnectionManager().getConnection() );
|
final Connection connection = session.getTransactionCoordinator()
|
||||||
session.getJDBCContext().getConnectionManager().afterStatement();
|
.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getShareableConnectionProxy();
|
||||||
|
work.execute( connection );
|
||||||
|
session.getTransactionCoordinator()
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.afterStatementExecution();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// at the very least cleanup the data :)
|
// at the very least cleanup the data :)
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
ps = session.getJDBCContext().getConnectionManager().prepareStatement( "delete from " + persister.getTemporaryIdTableName(),
|
final String sql = "delete from " + persister.getTemporaryIdTableName();
|
||||||
false
|
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||||
);
|
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
catch( Throwable t ) {
|
catch( Throwable t ) {
|
||||||
|
|
|
@ -84,7 +84,7 @@ public class BasicExecutor extends AbstractStatementExecutor {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
st = session.getJDBCContext().getConnectionManager().prepareStatement( sql, false );
|
st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||||
Iterator parameterSpecifications = this.parameterSpecifications.iterator();
|
Iterator parameterSpecifications = this.parameterSpecifications.iterator();
|
||||||
int pos = 1;
|
int pos = 1;
|
||||||
while ( parameterSpecifications.hasNext() ) {
|
while ( parameterSpecifications.hasNext() ) {
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class MultiTableDeleteExecutor extends AbstractStatementExecutor {
|
||||||
int resultCount = 0;
|
int resultCount = 0;
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
ps = session.getJDBCContext().getConnectionManager().prepareStatement( idInsertSelect, false );
|
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( idInsertSelect, false );
|
||||||
Iterator paramSpecifications = getIdSelectParameterSpecifications().iterator();
|
Iterator paramSpecifications = getIdSelectParameterSpecifications().iterator();
|
||||||
int pos = 1;
|
int pos = 1;
|
||||||
while ( paramSpecifications.hasNext() ) {
|
while ( paramSpecifications.hasNext() ) {
|
||||||
|
@ -132,7 +132,7 @@ public class MultiTableDeleteExecutor extends AbstractStatementExecutor {
|
||||||
for ( int i = 0; i < deletes.length; i++ ) {
|
for ( int i = 0; i < deletes.length; i++ ) {
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
ps = session.getJDBCContext().getConnectionManager().prepareStatement( deletes[i], false );
|
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( deletes[i], false );
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|
|
@ -129,7 +129,7 @@ public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
|
||||||
int resultCount = 0;
|
int resultCount = 0;
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
ps = session.getJDBCContext().getConnectionManager().prepareStatement( idInsertSelect, false );
|
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( idInsertSelect, false );
|
||||||
// int parameterStart = getWalker().getNumberOfParametersInSetClause();
|
// int parameterStart = getWalker().getNumberOfParametersInSetClause();
|
||||||
// List allParams = getIdSelectParameterSpecifications();
|
// List allParams = getIdSelectParameterSpecifications();
|
||||||
// Iterator whereParams = allParams.subList( parameterStart, allParams.size() ).iterator();
|
// Iterator whereParams = allParams.subList( parameterStart, allParams.size() ).iterator();
|
||||||
|
@ -161,7 +161,7 @@ public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
ps = session.getJDBCContext().getConnectionManager().prepareStatement( updates[i], false );
|
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( updates[i], false );
|
||||||
if ( hqlParameters[i] != null ) {
|
if ( hqlParameters[i] != null ) {
|
||||||
int position = 1; // jdbc params are 1-based
|
int position = 1; // jdbc params are 1-based
|
||||||
for ( int x = 0; x < hqlParameters[i].length; x++ ) {
|
for ( int x = 0; x < hqlParameters[i].length; x++ ) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class GUIDGenerator implements IdentifierGenerator {
|
||||||
|
|
||||||
final String sql = session.getFactory().getDialect().getSelectGUIDString();
|
final String sql = session.getFactory().getDialect().getSelectGUIDString();
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement(sql);
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
ResultSet rs = st.executeQuery();
|
ResultSet rs = st.executeQuery();
|
||||||
final String result;
|
final String result;
|
||||||
|
|
|
@ -87,7 +87,10 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
||||||
return session.getJDBCContext().getConnectionManager().prepareStatement( insertSQL, PreparedStatement.RETURN_GENERATED_KEYS );
|
return session.getTransactionCoordinator()
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getStatementPreparer()
|
||||||
|
.prepareStatement( insertSQL, PreparedStatement.RETURN_GENERATED_KEYS );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
|
public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
|
||||||
|
@ -131,7 +134,10 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
||||||
return session.getJDBCContext().getConnectionManager().prepareStatement( insertSQL, PreparedStatement.NO_GENERATED_KEYS );
|
return session.getTransactionCoordinator()
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getStatementPreparer()
|
||||||
|
.prepareStatement( insertSQL, PreparedStatement.NO_GENERATED_KEYS );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
|
public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
|
||||||
|
|
|
@ -121,7 +121,7 @@ public class IncrementGenerator implements IdentifierGenerator, Configurable {
|
||||||
|
|
||||||
log.debug( "fetching initial value: " + sql );
|
log.debug( "fetching initial value: " + sql );
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
ResultSet rs = st.executeQuery();
|
ResultSet rs = st.executeQuery();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -106,7 +106,7 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu
|
||||||
|
|
||||||
protected IntegralDataTypeHolder generateHolder(SessionImplementor session) {
|
protected IntegralDataTypeHolder generateHolder(SessionImplementor session) {
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
ResultSet rs = st.executeQuery();
|
ResultSet rs = st.executeQuery();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class SequenceIdentityGenerator extends SequenceGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
|
||||||
return session.getJDBCContext().getConnectionManager().prepareStatement( insertSQL, keyColumns );
|
return session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( insertSQL, keyColumns );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
|
protected Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
|
||||||
|
|
|
@ -102,7 +102,7 @@ public class SequenceStructure implements DatabaseStructure {
|
||||||
public IntegralDataTypeHolder getNextValue() {
|
public IntegralDataTypeHolder getNextValue() {
|
||||||
accessCounter++;
|
accessCounter++;
|
||||||
try {
|
try {
|
||||||
PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql );
|
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
|
||||||
try {
|
try {
|
||||||
ResultSet rs = st.executeQuery();
|
ResultSet rs = st.executeQuery();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -50,7 +50,10 @@ public abstract class AbstractSelectingDelegate implements InsertGeneratedIdenti
|
||||||
public final Serializable performInsert(String insertSQL, SessionImplementor session, Binder binder) {
|
public final Serializable performInsert(String insertSQL, SessionImplementor session, Binder binder) {
|
||||||
try {
|
try {
|
||||||
// prepare and execute the insert
|
// prepare and execute the insert
|
||||||
PreparedStatement insert = session.getJDBCContext().getConnectionManager().prepareStatement( insertSQL, PreparedStatement.NO_GENERATED_KEYS );
|
PreparedStatement insert = session.getTransactionCoordinator()
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getStatementPreparer()
|
||||||
|
.prepareStatement( insertSQL, PreparedStatement.NO_GENERATED_KEYS );
|
||||||
try {
|
try {
|
||||||
binder.bindValues( insert );
|
binder.bindValues( insert );
|
||||||
insert.executeUpdate();
|
insert.executeUpdate();
|
||||||
|
@ -71,7 +74,10 @@ public abstract class AbstractSelectingDelegate implements InsertGeneratedIdenti
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//fetch the generated id in a separate query
|
//fetch the generated id in a separate query
|
||||||
PreparedStatement idSelect = session.getJDBCContext().getConnectionManager().prepareStatement( selectSQL, false );
|
PreparedStatement idSelect = session.getTransactionCoordinator()
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getStatementPreparer()
|
||||||
|
.prepareStatement( selectSQL, false );
|
||||||
try {
|
try {
|
||||||
bindParameters( session, idSelect, binder.getEntity() );
|
bindParameters( session, idSelect, binder.getEntity() );
|
||||||
ResultSet rs = idSelect.executeQuery();
|
ResultSet rs = idSelect.executeQuery();
|
||||||
|
|
|
@ -38,6 +38,8 @@ import org.hibernate.engine.QueryParameters;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.query.HQLQueryPlan;
|
import org.hibernate.engine.query.HQLQueryPlan;
|
||||||
import org.hibernate.engine.query.NativeSQLQueryPlan;
|
import org.hibernate.engine.query.NativeSQLQueryPlan;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionContext;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -46,7 +48,7 @@ import java.util.List;
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractSessionImpl implements SessionImplementor {
|
public abstract class AbstractSessionImpl implements SessionImplementor, TransactionContext {
|
||||||
|
|
||||||
protected transient SessionFactoryImpl factory;
|
protected transient SessionFactoryImpl factory;
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
|
@ -59,6 +61,11 @@ public abstract class AbstractSessionImpl implements SessionImplementor {
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionEnvironment getTransactionEnvironment() {
|
||||||
|
return factory.getTransactionEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isClosed() {
|
public boolean isClosed() {
|
||||||
return closed;
|
return closed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.hibernate.impl;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InvalidObjectException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.ObjectStreamException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.Reference;
|
|
||||||
import javax.naming.StringRefAddr;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.Cache;
|
import org.hibernate.Cache;
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
|
@ -76,10 +50,6 @@ import org.hibernate.cache.impl.CacheDataDescriptionImpl;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
import org.hibernate.cfg.Settings;
|
import org.hibernate.cfg.Settings;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|
||||||
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
|
||||||
import org.hibernate.exception.SQLExceptionConverter;
|
|
||||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
|
||||||
import org.hibernate.context.CurrentSessionContext;
|
import org.hibernate.context.CurrentSessionContext;
|
||||||
import org.hibernate.context.JTASessionContext;
|
import org.hibernate.context.JTASessionContext;
|
||||||
import org.hibernate.context.ManagedSessionContext;
|
import org.hibernate.context.ManagedSessionContext;
|
||||||
|
@ -92,12 +62,16 @@ import org.hibernate.engine.NamedQueryDefinition;
|
||||||
import org.hibernate.engine.NamedSQLQueryDefinition;
|
import org.hibernate.engine.NamedSQLQueryDefinition;
|
||||||
import org.hibernate.engine.ResultSetMappingDefinition;
|
import org.hibernate.engine.ResultSetMappingDefinition;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
|
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
||||||
import org.hibernate.engine.profile.Association;
|
import org.hibernate.engine.profile.Association;
|
||||||
import org.hibernate.engine.profile.Fetch;
|
import org.hibernate.engine.profile.Fetch;
|
||||||
import org.hibernate.engine.profile.FetchProfile;
|
import org.hibernate.engine.profile.FetchProfile;
|
||||||
import org.hibernate.engine.query.QueryPlanCache;
|
import org.hibernate.engine.query.QueryPlanCache;
|
||||||
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
|
||||||
import org.hibernate.event.EventListeners;
|
import org.hibernate.event.EventListeners;
|
||||||
|
import org.hibernate.exception.SQLExceptionConverter;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
import org.hibernate.id.UUIDGenerator;
|
import org.hibernate.id.UUIDGenerator;
|
||||||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||||
|
@ -113,6 +87,8 @@ import org.hibernate.persister.entity.Loadable;
|
||||||
import org.hibernate.persister.entity.Queryable;
|
import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||||
|
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||||
|
import org.hibernate.service.jta.platform.spi.JtaPlatform;
|
||||||
import org.hibernate.service.spi.ServiceRegistry;
|
import org.hibernate.service.spi.ServiceRegistry;
|
||||||
import org.hibernate.stat.ConcurrentStatisticsImpl;
|
import org.hibernate.stat.ConcurrentStatisticsImpl;
|
||||||
import org.hibernate.stat.Statistics;
|
import org.hibernate.stat.Statistics;
|
||||||
|
@ -120,7 +96,6 @@ import org.hibernate.stat.StatisticsImplementor;
|
||||||
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
||||||
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
|
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
|
||||||
import org.hibernate.tool.hbm2ddl.SchemaValidator;
|
import org.hibernate.tool.hbm2ddl.SchemaValidator;
|
||||||
import org.hibernate.transaction.TransactionFactory;
|
|
||||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -128,6 +103,31 @@ import org.hibernate.type.TypeResolver;
|
||||||
import org.hibernate.util.CollectionHelper;
|
import org.hibernate.util.CollectionHelper;
|
||||||
import org.hibernate.util.EmptyIterator;
|
import org.hibernate.util.EmptyIterator;
|
||||||
import org.hibernate.util.ReflectHelper;
|
import org.hibernate.util.ReflectHelper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.naming.NamingException;
|
||||||
|
import javax.naming.Reference;
|
||||||
|
import javax.naming.StringRefAddr;
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InvalidObjectException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.ObjectStreamException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,7 +153,8 @@ import org.hibernate.util.ReflectHelper;
|
||||||
* @see org.hibernate.persister.collection.CollectionPersister
|
* @see org.hibernate.persister.collection.CollectionPersister
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor {
|
public final class SessionFactoryImpl
|
||||||
|
implements SessionFactory, SessionFactoryImplementor {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SessionFactoryImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(SessionFactoryImpl.class);
|
||||||
private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator();
|
private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator();
|
||||||
|
@ -178,7 +179,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
||||||
private final transient Settings settings;
|
private final transient Settings settings;
|
||||||
private final transient Properties properties;
|
private final transient Properties properties;
|
||||||
private transient SchemaExport schemaExport;
|
private transient SchemaExport schemaExport;
|
||||||
private final transient TransactionManager transactionManager;
|
|
||||||
private final transient QueryCache queryCache;
|
private final transient QueryCache queryCache;
|
||||||
private final transient UpdateTimestampsCache updateTimestampsCache;
|
private final transient UpdateTimestampsCache updateTimestampsCache;
|
||||||
private final transient Map<String,QueryCache> queryCaches;
|
private final transient Map<String,QueryCache> queryCaches;
|
||||||
|
@ -195,6 +195,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
||||||
private transient boolean isClosed = false;
|
private transient boolean isClosed = false;
|
||||||
private final transient TypeResolver typeResolver;
|
private final transient TypeResolver typeResolver;
|
||||||
private final transient TypeHelper typeHelper;
|
private final transient TypeHelper typeHelper;
|
||||||
|
private final transient TransactionEnvironment transactionEnvironment;
|
||||||
|
|
||||||
public SessionFactoryImpl(
|
public SessionFactoryImpl(
|
||||||
Configuration cfg,
|
Configuration cfg,
|
||||||
|
@ -386,17 +387,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
||||||
schemaExport = new SchemaExport( getJdbcServices(), cfg );
|
schemaExport = new SchemaExport( getJdbcServices(), cfg );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( settings.getTransactionManagerLookup()!=null ) {
|
|
||||||
log.debug("obtaining JTA TransactionManager");
|
|
||||||
transactionManager = settings.getTransactionManagerLookup().getTransactionManager(properties);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( settings.getTransactionFactory().isTransactionManagerRequired() ) {
|
|
||||||
throw new HibernateException("The chosen transaction strategy requires access to the JTA TransactionManager");
|
|
||||||
}
|
|
||||||
transactionManager = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentSessionContext = buildCurrentSessionContext();
|
currentSessionContext = buildCurrentSessionContext();
|
||||||
|
|
||||||
if ( settings.isQueryCacheEnabled() ) {
|
if ( settings.isQueryCacheEnabled() ) {
|
||||||
|
@ -480,9 +470,14 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
||||||
fetchProfiles.put( fetchProfile.getName(), fetchProfile );
|
fetchProfiles.put( fetchProfile.getName(), fetchProfile );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.transactionEnvironment = new TransactionEnvironmentImpl( this );
|
||||||
this.observer.sessionFactoryCreated( this );
|
this.observer.sessionFactoryCreated( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TransactionEnvironment getTransactionEnvironment() {
|
||||||
|
return transactionEnvironment;
|
||||||
|
}
|
||||||
|
|
||||||
public Properties getProperties() {
|
public Properties getProperties() {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
@ -728,14 +723,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
||||||
return interceptor;
|
return interceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransactionFactory getTransactionFactory() {
|
|
||||||
return settings.getTransactionFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransactionManager getTransactionManager() {
|
|
||||||
return transactionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SQLExceptionConverter getSQLExceptionConverter() {
|
public SQLExceptionConverter getSQLExceptionConverter() {
|
||||||
return getSQLExceptionHelper().getSqlExceptionConverter();
|
return getSQLExceptionHelper().getSqlExceptionConverter();
|
||||||
}
|
}
|
||||||
|
@ -1229,19 +1216,34 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
||||||
return (IdentifierGenerator) identifierGenerators.get(rootEntityName);
|
return (IdentifierGenerator) identifierGenerators.get(rootEntityName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private org.hibernate.engine.transaction.spi.TransactionFactory transactionFactory() {
|
||||||
|
return serviceRegistry.getService( org.hibernate.engine.transaction.spi.TransactionFactory.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canAccessTransactionManager() {
|
||||||
|
try {
|
||||||
|
return serviceRegistry.getService( JtaPlatform.class ).retrieveTransactionManager() != null;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private CurrentSessionContext buildCurrentSessionContext() {
|
private CurrentSessionContext buildCurrentSessionContext() {
|
||||||
String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
|
String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
|
||||||
// for backward-compatability
|
// for backward-compatibility
|
||||||
if ( impl == null && transactionManager != null ) {
|
if ( impl == null ) {
|
||||||
impl = "jta";
|
if ( canAccessTransactionManager() ) {
|
||||||
|
impl = "jta";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( impl == null ) {
|
if ( "jta".equals( impl ) ) {
|
||||||
return null;
|
if ( ! transactionFactory().compatibleWithJtaSynchronization() ) {
|
||||||
}
|
log.warn( "JTASessionContext being used with JdbcTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
|
||||||
else if ( "jta".equals( impl ) ) {
|
|
||||||
if ( settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions() ) {
|
|
||||||
log.warn( "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
|
|
||||||
}
|
}
|
||||||
return new JTASessionContext( this );
|
return new JTASessionContext( this );
|
||||||
}
|
}
|
||||||
|
@ -1256,7 +1258,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
||||||
Class implClass = ReflectHelper.classForName( impl );
|
Class implClass = ReflectHelper.classForName( impl );
|
||||||
return ( CurrentSessionContext ) implClass
|
return ( CurrentSessionContext ) implClass
|
||||||
.getConstructor( new Class[] { SessionFactoryImplementor.class } )
|
.getConstructor( new Class[] { SessionFactoryImplementor.class } )
|
||||||
.newInstance( new Object[] { this } );
|
.newInstance( this );
|
||||||
}
|
}
|
||||||
catch( Throwable t ) {
|
catch( Throwable t ) {
|
||||||
log.error( "Unable to construct current session context [" + impl + "]", t );
|
log.error( "Unable to construct current session context [" + impl + "]", t );
|
||||||
|
@ -1265,11 +1267,15 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventListeners getEventListeners()
|
public EventListeners getEventListeners() {
|
||||||
{
|
|
||||||
return eventListeners;
|
return eventListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServiceRegistry getServiceRegistry() {
|
||||||
|
return serviceRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
public EntityNotFoundDelegate getEntityNotFoundDelegate() {
|
public EntityNotFoundDelegate getEntityNotFoundDelegate() {
|
||||||
return entityNotFoundDelegate;
|
return entityNotFoundDelegate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2005-2011, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,44 +20,21 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.impl;
|
package org.hibernate.impl;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.sql.Blob;
|
|
||||||
import java.sql.Clob;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
import org.hibernate.Criteria;
|
import org.hibernate.Criteria;
|
||||||
import org.hibernate.EntityMode;
|
import org.hibernate.EntityMode;
|
||||||
|
import org.hibernate.EntityNameResolver;
|
||||||
import org.hibernate.Filter;
|
import org.hibernate.Filter;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Interceptor;
|
import org.hibernate.Interceptor;
|
||||||
import org.hibernate.LobHelper;
|
import org.hibernate.LobHelper;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.ObjectDeletedException;
|
import org.hibernate.ObjectDeletedException;
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
|
@ -68,33 +45,34 @@ import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.SessionException;
|
import org.hibernate.SessionException;
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
import org.hibernate.TransientObjectException;
|
import org.hibernate.TransientObjectException;
|
||||||
import org.hibernate.TypeHelper;
|
import org.hibernate.TypeHelper;
|
||||||
import org.hibernate.UnresolvableObjectException;
|
|
||||||
import org.hibernate.UnknownProfileException;
|
import org.hibernate.UnknownProfileException;
|
||||||
import org.hibernate.EntityNameResolver;
|
import org.hibernate.UnresolvableObjectException;
|
||||||
import org.hibernate.LockOptions;
|
|
||||||
import org.hibernate.collection.PersistentCollection;
|
import org.hibernate.collection.PersistentCollection;
|
||||||
import org.hibernate.engine.ActionQueue;
|
import org.hibernate.engine.ActionQueue;
|
||||||
import org.hibernate.engine.CollectionEntry;
|
import org.hibernate.engine.CollectionEntry;
|
||||||
import org.hibernate.engine.EntityEntry;
|
import org.hibernate.engine.EntityEntry;
|
||||||
import org.hibernate.engine.EntityKey;
|
import org.hibernate.engine.EntityKey;
|
||||||
|
import org.hibernate.engine.LoadQueryInfluencers;
|
||||||
import org.hibernate.engine.NonFlushedChanges;
|
import org.hibernate.engine.NonFlushedChanges;
|
||||||
import org.hibernate.engine.PersistenceContext;
|
import org.hibernate.engine.PersistenceContext;
|
||||||
import org.hibernate.engine.QueryParameters;
|
import org.hibernate.engine.QueryParameters;
|
||||||
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.StatefulPersistenceContext;
|
import org.hibernate.engine.StatefulPersistenceContext;
|
||||||
import org.hibernate.engine.Status;
|
import org.hibernate.engine.Status;
|
||||||
import org.hibernate.engine.LoadQueryInfluencers;
|
|
||||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||||
import org.hibernate.engine.jdbc.LobCreator;
|
import org.hibernate.engine.jdbc.LobCreator;
|
||||||
import org.hibernate.engine.jdbc.internal.JDBCContextImpl;
|
|
||||||
import org.hibernate.engine.jdbc.spi.JDBCContext;
|
|
||||||
import org.hibernate.engine.query.FilterQueryPlan;
|
import org.hibernate.engine.query.FilterQueryPlan;
|
||||||
import org.hibernate.engine.query.HQLQueryPlan;
|
import org.hibernate.engine.query.HQLQueryPlan;
|
||||||
import org.hibernate.engine.query.NativeSQLQueryPlan;
|
import org.hibernate.engine.query.NativeSQLQueryPlan;
|
||||||
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
||||||
|
import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionContext;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionObserver;
|
||||||
import org.hibernate.event.AutoFlushEvent;
|
import org.hibernate.event.AutoFlushEvent;
|
||||||
import org.hibernate.event.AutoFlushEventListener;
|
import org.hibernate.event.AutoFlushEventListener;
|
||||||
import org.hibernate.event.DeleteEvent;
|
import org.hibernate.event.DeleteEvent;
|
||||||
|
@ -136,57 +114,84 @@ import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.proxy.LazyInitializer;
|
import org.hibernate.proxy.LazyInitializer;
|
||||||
import org.hibernate.stat.SessionStatistics;
|
import org.hibernate.stat.SessionStatistics;
|
||||||
import org.hibernate.stat.SessionStatisticsImpl;
|
import org.hibernate.stat.SessionStatisticsImpl;
|
||||||
import org.hibernate.type.Type;
|
|
||||||
import org.hibernate.type.SerializationException;
|
import org.hibernate.type.SerializationException;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.util.ArrayHelper;
|
import org.hibernate.util.ArrayHelper;
|
||||||
import org.hibernate.util.CollectionHelper;
|
import org.hibernate.util.CollectionHelper;
|
||||||
import org.hibernate.util.StringHelper;
|
import org.hibernate.util.StringHelper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.Blob;
|
||||||
|
import java.sql.Clob;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concrete implementation of a Session, and also the central, organizing component
|
* Concrete implementation of a Session.
|
||||||
* of Hibernate's internal implementation. As such, this class exposes two interfaces;
|
*
|
||||||
* Session itself, to the application, and SessionImplementor, to other components
|
* Exposes two interfaces:<ul>
|
||||||
* of Hibernate. This class is not threadsafe.
|
* <li>{@link Session} to the application</li>
|
||||||
|
* <li>{@link org.hibernate.engine.SessionImplementor} to other Hibernate components (SPI)</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* This class is not thread-safe.
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public final class SessionImpl extends AbstractSessionImpl
|
public final class SessionImpl
|
||||||
implements EventSource, org.hibernate.classic.Session, JDBCContext.Context, LobCreationContext {
|
extends AbstractSessionImpl
|
||||||
|
implements EventSource,
|
||||||
|
org.hibernate.classic.Session,
|
||||||
|
TransactionContext,
|
||||||
|
LobCreationContext {
|
||||||
|
|
||||||
// todo : need to find a clean way to handle the "event source" role
|
// todo : need to find a clean way to handle the "event source" role
|
||||||
// a seperate classs responsible for generating/dispatching events just duplicates most of the Session methods...
|
// a separate class responsible for generating/dispatching events just duplicates most of the Session methods...
|
||||||
// passing around seperate reto interceptor, factory, actionQueue, and persistentContext is not manageable...
|
// passing around separate interceptor, factory, actionQueue, and persistentContext is not manageable...
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SessionImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(SessionImpl.class);
|
||||||
|
|
||||||
private transient EntityMode entityMode = EntityMode.POJO;
|
|
||||||
private transient boolean autoClear; //for EJB3
|
|
||||||
|
|
||||||
private transient long timestamp;
|
private transient long timestamp;
|
||||||
private transient FlushMode flushMode = FlushMode.AUTO;
|
|
||||||
private transient CacheMode cacheMode = CacheMode.NORMAL;
|
|
||||||
|
|
||||||
private transient Interceptor interceptor;
|
|
||||||
|
|
||||||
private transient int dontFlushFromFind = 0;
|
|
||||||
|
|
||||||
private transient ActionQueue actionQueue;
|
private transient ActionQueue actionQueue;
|
||||||
private transient StatefulPersistenceContext persistenceContext;
|
private transient StatefulPersistenceContext persistenceContext;
|
||||||
private transient JDBCContextImpl jdbcContext;
|
private transient TransactionCoordinatorImpl transactionCoordinator;
|
||||||
private transient EventListeners listeners;
|
private transient EventListeners listeners;
|
||||||
|
private transient Interceptor interceptor;
|
||||||
|
private transient EntityNameResolver entityNameResolver = new CoordinatingEntityNameResolver();
|
||||||
|
|
||||||
|
private transient ConnectionReleaseMode connectionReleaseMode;
|
||||||
|
private transient FlushMode flushMode = FlushMode.AUTO;
|
||||||
|
private transient CacheMode cacheMode = CacheMode.NORMAL;
|
||||||
|
private transient EntityMode entityMode = EntityMode.POJO;
|
||||||
|
private transient boolean autoClear; //for EJB3
|
||||||
|
|
||||||
|
private transient int dontFlushFromFind = 0;
|
||||||
private transient boolean flushBeforeCompletionEnabled;
|
private transient boolean flushBeforeCompletionEnabled;
|
||||||
private transient boolean autoCloseSessionEnabled;
|
private transient boolean autoCloseSessionEnabled;
|
||||||
private transient ConnectionReleaseMode connectionReleaseMode;
|
|
||||||
|
|
||||||
private transient LoadQueryInfluencers loadQueryInfluencers;
|
private transient LoadQueryInfluencers loadQueryInfluencers;
|
||||||
|
|
||||||
private transient Session rootSession;
|
private transient Session rootSession;
|
||||||
private transient Map childSessionsByEntityMode;
|
private transient Map childSessionsByEntityMode;
|
||||||
|
|
||||||
private transient EntityNameResolver entityNameResolver = new CoordinatingEntityNameResolver();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor used in building "child sessions".
|
* Constructor used in building "child sessions".
|
||||||
*
|
*
|
||||||
|
@ -197,7 +202,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
super( parent.factory );
|
super( parent.factory );
|
||||||
this.rootSession = parent;
|
this.rootSession = parent;
|
||||||
this.timestamp = parent.timestamp;
|
this.timestamp = parent.timestamp;
|
||||||
this.jdbcContext = parent.jdbcContext;
|
this.transactionCoordinator = parent.transactionCoordinator;
|
||||||
this.interceptor = parent.interceptor;
|
this.interceptor = parent.interceptor;
|
||||||
this.listeners = parent.listeners;
|
this.listeners = parent.listeners;
|
||||||
this.actionQueue = new ActionQueue( this );
|
this.actionQueue = new ActionQueue( this );
|
||||||
|
@ -251,7 +256,11 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
|
this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
|
||||||
this.autoCloseSessionEnabled = autoCloseSessionEnabled;
|
this.autoCloseSessionEnabled = autoCloseSessionEnabled;
|
||||||
this.connectionReleaseMode = connectionReleaseMode;
|
this.connectionReleaseMode = connectionReleaseMode;
|
||||||
this.jdbcContext = new JDBCContextImpl( this, connection, interceptor );
|
|
||||||
|
this.transactionCoordinator = new TransactionCoordinatorImpl( connection, this );
|
||||||
|
this.transactionCoordinator.getJdbcCoordinator().getLogicalConnection().addObserver(
|
||||||
|
new ConnectionObserverStatsBridge( factory )
|
||||||
|
);
|
||||||
|
|
||||||
loadQueryInfluencers = new LoadQueryInfluencers( factory );
|
loadQueryInfluencers = new LoadQueryInfluencers( factory );
|
||||||
|
|
||||||
|
@ -330,7 +339,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( rootSession == null ) {
|
if ( rootSession == null ) {
|
||||||
return jdbcContext.getConnectionManager().close();
|
return transactionCoordinator.close();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -343,7 +352,6 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionReleaseMode getConnectionReleaseMode() {
|
public ConnectionReleaseMode getConnectionReleaseMode() {
|
||||||
checkTransactionSynchStatus();
|
|
||||||
return connectionReleaseMode;
|
return connectionReleaseMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,76 +531,84 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public Connection connection() throws HibernateException {
|
public Connection connection() throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
return jdbcContext.borrowConnection();
|
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getDistinctConnectionProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return !isClosed() && jdbcContext.getConnectionManager().isCurrentlyConnected();
|
return !isClosed() && transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTransactionInProgress() {
|
public boolean isTransactionInProgress() {
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return !isClosed() && jdbcContext.isTransactionInProgress();
|
return !isClosed() && transactionCoordinator.isTransactionInProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Connection disconnect() throws HibernateException {
|
public Connection disconnect() throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
log.debug( "disconnecting session" );
|
log.debug( "disconnecting session" );
|
||||||
return jdbcContext.getConnectionManager().manualDisconnect();
|
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualDisconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reconnect() throws HibernateException {
|
public void reconnect() throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
log.debug( "reconnecting session" );
|
log.debug( "reconnecting session" );
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
jdbcContext.getConnectionManager().manualReconnect();
|
transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualReconnect( null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reconnect(Connection conn) throws HibernateException {
|
public void reconnect(Connection conn) throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
log.debug( "reconnecting session" );
|
log.debug( "reconnecting session" );
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
jdbcContext.getConnectionManager().manualReconnect( conn );
|
transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualReconnect( conn );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beforeTransactionCompletion(Transaction tx) {
|
|
||||||
log.trace( "before transaction completion" );
|
|
||||||
actionQueue.beforeTransactionCompletion();
|
|
||||||
if ( rootSession == null ) {
|
|
||||||
try {
|
|
||||||
interceptor.beforeTransactionCompletion(tx);
|
|
||||||
}
|
|
||||||
catch (Throwable t) {
|
|
||||||
log.error("exception in interceptor beforeTransactionCompletion()", t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAutoClear(boolean enabled) {
|
public void setAutoClear(boolean enabled) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
autoClear = enabled;
|
autoClear = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if there is a Hibernate or JTA transaction in progress and,
|
* Check if there is a Hibernate or JTA transaction in progress and,
|
||||||
* if there is not, flush if necessary, make sure the connection has
|
* if there is not, flush if necessary, make sure the connection has
|
||||||
* been committed (if it is not in autocommit mode) and run the after
|
* been committed (if it is not in autocommit mode) and run the after
|
||||||
* completion processing
|
* completion processing
|
||||||
*/
|
*/
|
||||||
public void afterOperation(boolean success) {
|
public void afterOperation(boolean success) {
|
||||||
if ( !jdbcContext.isTransactionInProgress() ) {
|
if ( ! transactionCoordinator.isTransactionInProgress() ) {
|
||||||
jdbcContext.afterNontransactionalQuery( success );
|
transactionCoordinator.afterNonTransactionalQuery( success );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterTransactionCompletion(boolean success, Transaction tx) {
|
@Override
|
||||||
|
public void afterTransactionBegin(TransactionImplementor hibernateTransaction) {
|
||||||
|
errorIfClosed();
|
||||||
|
interceptor.afterTransactionBegin( hibernateTransaction );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTransactionCompletion(TransactionImplementor hibernateTransaction) {
|
||||||
|
log.trace( "before transaction completion" );
|
||||||
|
actionQueue.beforeTransactionCompletion();
|
||||||
|
if ( rootSession == null ) {
|
||||||
|
try {
|
||||||
|
interceptor.beforeTransactionCompletion( hibernateTransaction );
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
log.error( "exception in interceptor beforeTransactionCompletion()", t );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTransactionCompletion(TransactionImplementor hibernateTransaction, boolean successful) {
|
||||||
log.trace( "after transaction completion" );
|
log.trace( "after transaction completion" );
|
||||||
persistenceContext.afterTransactionCompletion();
|
persistenceContext.afterTransactionCompletion();
|
||||||
actionQueue.afterTransactionCompletion(success);
|
actionQueue.afterTransactionCompletion( successful );
|
||||||
if ( rootSession == null && tx != null ) {
|
if ( rootSession == null && hibernateTransaction != null ) {
|
||||||
try {
|
try {
|
||||||
interceptor.afterTransactionCompletion(tx);
|
interceptor.afterTransactionCompletion( hibernateTransaction );
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
log.error("exception in interceptor afterTransactionCompletion()", t);
|
log.error("exception in interceptor afterTransactionCompletion()", t);
|
||||||
|
@ -660,11 +676,11 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
// saveOrUpdate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// saveOrUpdate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
public void saveOrUpdate(Object object) throws HibernateException {
|
public void saveOrUpdate(Object object) throws HibernateException {
|
||||||
saveOrUpdate(null, object);
|
saveOrUpdate( null, object );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveOrUpdate(String entityName, Object obj) throws HibernateException {
|
public void saveOrUpdate(String entityName, Object obj) throws HibernateException {
|
||||||
fireSaveOrUpdate( new SaveOrUpdateEvent(entityName, obj, this) );
|
fireSaveOrUpdate( new SaveOrUpdateEvent( entityName, obj, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireSaveOrUpdate(SaveOrUpdateEvent event) {
|
private void fireSaveOrUpdate(SaveOrUpdateEvent event) {
|
||||||
|
@ -684,15 +700,15 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serializable save(Object obj) throws HibernateException {
|
public Serializable save(Object obj) throws HibernateException {
|
||||||
return save(null, obj);
|
return save( null, obj );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serializable save(String entityName, Object object) throws HibernateException {
|
public Serializable save(String entityName, Object object) throws HibernateException {
|
||||||
return fireSave( new SaveOrUpdateEvent(entityName, object, this) );
|
return fireSave( new SaveOrUpdateEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(String entityName, Object object, Serializable id) throws HibernateException {
|
public void save(String entityName, Object object, Serializable id) throws HibernateException {
|
||||||
fireSave( new SaveOrUpdateEvent(entityName, object, id, this) );
|
fireSave( new SaveOrUpdateEvent( entityName, object, id, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Serializable fireSave(SaveOrUpdateEvent event) {
|
private Serializable fireSave(SaveOrUpdateEvent event) {
|
||||||
|
@ -713,15 +729,15 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(Object obj, Serializable id) throws HibernateException {
|
public void update(Object obj, Serializable id) throws HibernateException {
|
||||||
update(null, obj, id);
|
update( null, obj, id );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(String entityName, Object object) throws HibernateException {
|
public void update(String entityName, Object object) throws HibernateException {
|
||||||
fireUpdate( new SaveOrUpdateEvent(entityName, object, this) );
|
fireUpdate( new SaveOrUpdateEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(String entityName, Object object, Serializable id) throws HibernateException {
|
public void update(String entityName, Object object, Serializable id) throws HibernateException {
|
||||||
fireUpdate(new SaveOrUpdateEvent(entityName, object, id, this));
|
fireUpdate( new SaveOrUpdateEvent( entityName, object, id, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireUpdate(SaveOrUpdateEvent event) {
|
private void fireUpdate(SaveOrUpdateEvent event) {
|
||||||
|
@ -753,7 +769,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireLock( Object object, LockOptions options) {
|
private void fireLock( Object object, LockOptions options) {
|
||||||
fireLock( new LockEvent( object, options, this) );
|
fireLock( new LockEvent( object, options, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireLock(LockEvent lockEvent) {
|
private void fireLock(LockEvent lockEvent) {
|
||||||
|
@ -769,16 +785,16 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
// persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
public void persist(String entityName, Object object) throws HibernateException {
|
public void persist(String entityName, Object object) throws HibernateException {
|
||||||
firePersist( new PersistEvent(entityName, object, this) );
|
firePersist( new PersistEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void persist(Object object) throws HibernateException {
|
public void persist(Object object) throws HibernateException {
|
||||||
persist(null, object);
|
persist( null, object );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void persist(String entityName, Object object, Map copiedAlready)
|
public void persist(String entityName, Object object, Map copiedAlready)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
firePersist( copiedAlready, new PersistEvent(entityName, object, this) );
|
firePersist( copiedAlready, new PersistEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void firePersist(Map copiedAlready, PersistEvent event) {
|
private void firePersist(Map copiedAlready, PersistEvent event) {
|
||||||
|
@ -804,16 +820,16 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public void persistOnFlush(String entityName, Object object)
|
public void persistOnFlush(String entityName, Object object)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
firePersistOnFlush( new PersistEvent(entityName, object, this) );
|
firePersistOnFlush( new PersistEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void persistOnFlush(Object object) throws HibernateException {
|
public void persistOnFlush(Object object) throws HibernateException {
|
||||||
persist(null, object);
|
persist( null, object );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void persistOnFlush(String entityName, Object object, Map copiedAlready)
|
public void persistOnFlush(String entityName, Object object, Map copiedAlready)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
firePersistOnFlush( copiedAlready, new PersistEvent(entityName, object, this) );
|
firePersistOnFlush( copiedAlready, new PersistEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void firePersistOnFlush(Map copiedAlready, PersistEvent event) {
|
private void firePersistOnFlush(Map copiedAlready, PersistEvent event) {
|
||||||
|
@ -838,15 +854,15 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
// merge() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// merge() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
public Object merge(String entityName, Object object) throws HibernateException {
|
public Object merge(String entityName, Object object) throws HibernateException {
|
||||||
return fireMerge( new MergeEvent(entityName, object, this) );
|
return fireMerge( new MergeEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object merge(Object object) throws HibernateException {
|
public Object merge(Object object) throws HibernateException {
|
||||||
return merge(null, object);
|
return merge( null, object );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException {
|
public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException {
|
||||||
fireMerge( copiedAlready, new MergeEvent(entityName, object, this) );
|
fireMerge( copiedAlready, new MergeEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object fireMerge(MergeEvent event) {
|
private Object fireMerge(MergeEvent event) {
|
||||||
|
@ -873,7 +889,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public Object saveOrUpdateCopy(String entityName, Object object)
|
public Object saveOrUpdateCopy(String entityName, Object object)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
return fireSaveOrUpdateCopy( new MergeEvent(entityName, object, this) );
|
return fireSaveOrUpdateCopy( new MergeEvent( entityName, object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object saveOrUpdateCopy(Object object) throws HibernateException {
|
public Object saveOrUpdateCopy(Object object) throws HibernateException {
|
||||||
|
@ -882,7 +898,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public Object saveOrUpdateCopy(String entityName, Object object, Serializable id)
|
public Object saveOrUpdateCopy(String entityName, Object object, Serializable id)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
return fireSaveOrUpdateCopy( new MergeEvent(entityName, object, id, this) );
|
return fireSaveOrUpdateCopy( new MergeEvent( entityName, object, id, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object saveOrUpdateCopy(Object object, Serializable id)
|
public Object saveOrUpdateCopy(Object object, Serializable id)
|
||||||
|
@ -1037,7 +1053,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object load(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException {
|
public Object load(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException {
|
||||||
return load( entityClass.getName(), id, lockOptions);
|
return load( entityClass.getName(), id, lockOptions );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
|
public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
|
||||||
|
@ -1057,7 +1073,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException {
|
public Object get(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException {
|
||||||
return get( entityClass.getName(), id, lockOptions);
|
return get( entityClass.getName(), id, lockOptions );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
|
public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
|
||||||
|
@ -1068,7 +1084,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public Object get(String entityName, Serializable id, LockOptions lockOptions) throws HibernateException {
|
public Object get(String entityName, Serializable id, LockOptions lockOptions) throws HibernateException {
|
||||||
LoadEvent event = new LoadEvent(id, entityName, lockOptions, this);
|
LoadEvent event = new LoadEvent(id, entityName, lockOptions, this);
|
||||||
fireLoad(event, LoadEventListener.GET);
|
fireLoad( event, LoadEventListener.GET );
|
||||||
return event.getResult();
|
return event.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1097,7 +1113,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh(Object object, Map refreshedAlready) throws HibernateException {
|
public void refresh(Object object, Map refreshedAlready) throws HibernateException {
|
||||||
fireRefresh( refreshedAlready, new RefreshEvent(object, this) );
|
fireRefresh( refreshedAlready, new RefreshEvent( object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireRefresh(RefreshEvent refreshEvent) {
|
private void fireRefresh(RefreshEvent refreshEvent) {
|
||||||
|
@ -1127,7 +1143,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public void replicate(String entityName, Object obj, ReplicationMode replicationMode)
|
public void replicate(String entityName, Object obj, ReplicationMode replicationMode)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
fireReplicate( new ReplicateEvent(entityName, obj, replicationMode, this) );
|
fireReplicate( new ReplicateEvent( entityName, obj, replicationMode, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireReplicate(ReplicateEvent event) {
|
private void fireReplicate(ReplicateEvent event) {
|
||||||
|
@ -1147,7 +1163,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
* (references held by application or other persistant instances are okay)
|
* (references held by application or other persistant instances are okay)
|
||||||
*/
|
*/
|
||||||
public void evict(Object object) throws HibernateException {
|
public void evict(Object object) throws HibernateException {
|
||||||
fireEvict( new EvictEvent(object, this) );
|
fireEvict( new EvictEvent( object, this ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireEvict(EvictEvent evictEvent) {
|
private void fireEvict(EvictEvent evictEvent) {
|
||||||
|
@ -1289,7 +1305,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
queryParameters.validateParameters();
|
queryParameters.validateParameters();
|
||||||
NativeSQLQueryPlan plan = getNativeSQLQueryPlan(nativeQuerySpecification);
|
NativeSQLQueryPlan plan = getNativeSQLQueryPlan( nativeQuerySpecification );
|
||||||
|
|
||||||
|
|
||||||
autoFlushIfRequired( plan.getCustomQuery().getQuerySpaces() );
|
autoFlushIfRequired( plan.getCustomQuery().getQuerySpaces() );
|
||||||
|
@ -1394,11 +1410,11 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
public Query getNamedQuery(String queryName) throws MappingException {
|
public Query getNamedQuery(String queryName) throws MappingException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return super.getNamedQuery(queryName);
|
return super.getNamedQuery( queryName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object instantiate(String entityName, Serializable id) throws HibernateException {
|
public Object instantiate(String entityName, Serializable id) throws HibernateException {
|
||||||
return instantiate( factory.getEntityPersister(entityName), id );
|
return instantiate( factory.getEntityPersister( entityName ), id );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1449,7 +1465,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public Transaction getTransaction() throws HibernateException {
|
public Transaction getTransaction() throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
return jdbcContext.getTransaction();
|
return transactionCoordinator.getTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transaction beginTransaction() throws HibernateException {
|
public Transaction beginTransaction() throws HibernateException {
|
||||||
|
@ -1463,11 +1479,6 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
result.begin();
|
result.begin();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterTransactionBegin(Transaction tx) {
|
|
||||||
errorIfClosed();
|
|
||||||
interceptor.afterTransactionBegin(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityPersister getEntityPersister(final String entityName, final Object object) {
|
public EntityPersister getEntityPersister(final String entityName, final Object object) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
|
@ -1522,7 +1533,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
public Serializable getContextEntityIdentifier(Object object) {
|
public Serializable getContextEntityIdentifier(Object object) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
if ( object instanceof HibernateProxy ) {
|
if ( object instanceof HibernateProxy ) {
|
||||||
return getProxyIdentifier(object);
|
return getProxyIdentifier( object );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
EntityEntry entry = persistenceContext.getEntry(object);
|
EntityEntry entry = persistenceContext.getEntry(object);
|
||||||
|
@ -1757,13 +1768,13 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
public Query createQuery(String queryString) {
|
public Query createQuery(String queryString) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return super.createQuery(queryString);
|
return super.createQuery( queryString );
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLQuery createSQLQuery(String sql) {
|
public SQLQuery createSQLQuery(String sql) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return super.createSQLQuery(sql);
|
return super.createSQLQuery( sql );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query createSQLQuery(String sql, String returnAlias, Class returnClass) {
|
public Query createSQLQuery(String sql, String returnAlias, Class returnClass) {
|
||||||
|
@ -1839,11 +1850,11 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SessionFactory getSessionFactory() {
|
public SessionFactoryImplementor getSessionFactory() {
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeCollection(PersistentCollection collection, boolean writing)
|
public void initializeCollection(PersistentCollection collection, boolean writing)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
|
@ -1858,7 +1869,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
if (object instanceof HibernateProxy) {
|
if (object instanceof HibernateProxy) {
|
||||||
LazyInitializer initializer = ( ( HibernateProxy ) object ).getHibernateLazyInitializer();
|
LazyInitializer initializer = ( ( HibernateProxy ) object ).getHibernateLazyInitializer();
|
||||||
// it is possible for this method to be called during flush processing,
|
// it is possible for this method to be called during flush processing,
|
||||||
// so make certain that we do not accidently initialize an uninitialized proxy
|
// so make certain that we do not accidentally initialize an uninitialized proxy
|
||||||
if ( initializer.isUninitialized() ) {
|
if ( initializer.isUninitialized() ) {
|
||||||
return initializer.getEntityName();
|
return initializer.getEntityName();
|
||||||
}
|
}
|
||||||
|
@ -1904,7 +1915,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public void cancelQuery() throws HibernateException {
|
public void cancelQuery() throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
getJDBCContext().getConnectionManager().cancelLastQuery();
|
getTransactionCoordinator().getJdbcCoordinator().cancelLastQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Interceptor getInterceptor() {
|
public Interceptor getInterceptor() {
|
||||||
|
@ -1983,23 +1994,17 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doWork(Work work) throws HibernateException {
|
public void doWork(Work work) throws HibernateException {
|
||||||
try {
|
transactionCoordinator.getJdbcCoordinator().coordinateWork( work );
|
||||||
work.execute( jdbcContext.getConnectionManager().getConnection() );
|
|
||||||
jdbcContext.getConnectionManager().afterStatement();
|
|
||||||
}
|
|
||||||
catch ( SQLException e ) {
|
|
||||||
throw factory.getSQLExceptionHelper().convert( e, "error executing work" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterScrollOperation() {
|
public void afterScrollOperation() {
|
||||||
// nothing to do in a stateful session
|
// nothing to do in a stateful session
|
||||||
}
|
}
|
||||||
|
|
||||||
public JDBCContext getJDBCContext() {
|
@Override
|
||||||
|
public TransactionCoordinator getTransactionCoordinator() {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
return transactionCoordinator;
|
||||||
return jdbcContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoadQueryInfluencers getLoadQueryInfluencers() {
|
public LoadQueryInfluencers getLoadQueryInfluencers() {
|
||||||
|
@ -2098,8 +2103,8 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
|
|
||||||
private void checkTransactionSynchStatus() {
|
private void checkTransactionSynchStatus() {
|
||||||
if ( jdbcContext != null && !isClosed() ) {
|
if ( !isClosed() ) {
|
||||||
jdbcContext.registerSynchronizationIfPossible();
|
transactionCoordinator.pulse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2131,7 +2136,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
listeners = factory.getEventListeners();
|
listeners = factory.getEventListeners();
|
||||||
|
|
||||||
if ( isRootSession ) {
|
if ( isRootSession ) {
|
||||||
jdbcContext = JDBCContextImpl.deserialize( ois, this, interceptor );
|
transactionCoordinator = TransactionCoordinatorImpl.deserialize( ois, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
|
persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
|
||||||
|
@ -2156,7 +2161,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
while ( iter.hasNext() ) {
|
while ( iter.hasNext() ) {
|
||||||
final SessionImpl child = ( ( SessionImpl ) iter.next() );
|
final SessionImpl child = ( ( SessionImpl ) iter.next() );
|
||||||
child.rootSession = this;
|
child.rootSession = this;
|
||||||
child.jdbcContext = this.jdbcContext;
|
child.transactionCoordinator = this.transactionCoordinator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2168,7 +2173,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
* @throws IOException Indicates a general IO stream exception
|
* @throws IOException Indicates a general IO stream exception
|
||||||
*/
|
*/
|
||||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||||
if ( !jdbcContext.isReadyForSerialization() ) {
|
if ( ! transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isReadyForSerialization() ) {
|
||||||
throw new IllegalStateException( "Cannot serialize a session while connected" );
|
throw new IllegalStateException( "Cannot serialize a session while connected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2190,7 +2195,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
factory.serialize( oos );
|
factory.serialize( oos );
|
||||||
|
|
||||||
if ( rootSession == null ) {
|
if ( rootSession == null ) {
|
||||||
jdbcContext.serialize( oos );
|
transactionCoordinator.serialize( oos );
|
||||||
}
|
}
|
||||||
|
|
||||||
persistenceContext.serialize( oos );
|
persistenceContext.serialize( oos );
|
||||||
|
@ -2204,8 +2209,8 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public Object execute(Callback callback) {
|
public Object execute(LobCreationContext.Callback callback) {
|
||||||
Connection connection = jdbcContext.getConnectionManager().getConnection();
|
Connection connection = transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getConnection();
|
||||||
try {
|
try {
|
||||||
return callback.executeOnConnection( connection );
|
return callback.executeOnConnection( connection );
|
||||||
}
|
}
|
||||||
|
@ -2216,7 +2221,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
jdbcContext.getConnectionManager().afterStatement();
|
transactionCoordinator.getJdbcCoordinator().getLogicalConnection().afterStatementExecution();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,16 +21,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.impl;
|
package org.hibernate.impl;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
import org.hibernate.Criteria;
|
import org.hibernate.Criteria;
|
||||||
|
@ -50,17 +40,19 @@ import org.hibernate.UnresolvableObjectException;
|
||||||
import org.hibernate.cache.CacheKey;
|
import org.hibernate.cache.CacheKey;
|
||||||
import org.hibernate.collection.PersistentCollection;
|
import org.hibernate.collection.PersistentCollection;
|
||||||
import org.hibernate.engine.EntityKey;
|
import org.hibernate.engine.EntityKey;
|
||||||
|
import org.hibernate.engine.LoadQueryInfluencers;
|
||||||
|
import org.hibernate.engine.NonFlushedChanges;
|
||||||
import org.hibernate.engine.PersistenceContext;
|
import org.hibernate.engine.PersistenceContext;
|
||||||
import org.hibernate.engine.QueryParameters;
|
import org.hibernate.engine.QueryParameters;
|
||||||
import org.hibernate.engine.StatefulPersistenceContext;
|
import org.hibernate.engine.StatefulPersistenceContext;
|
||||||
import org.hibernate.engine.Versioning;
|
import org.hibernate.engine.Versioning;
|
||||||
import org.hibernate.engine.LoadQueryInfluencers;
|
|
||||||
import org.hibernate.engine.NonFlushedChanges;
|
|
||||||
import org.hibernate.engine.jdbc.internal.JDBCContextImpl;
|
|
||||||
import org.hibernate.engine.jdbc.spi.JDBCContext;
|
|
||||||
import org.hibernate.engine.query.HQLQueryPlan;
|
import org.hibernate.engine.query.HQLQueryPlan;
|
||||||
import org.hibernate.engine.query.NativeSQLQueryPlan;
|
import org.hibernate.engine.query.NativeSQLQueryPlan;
|
||||||
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
||||||
|
import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
|
||||||
|
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
||||||
import org.hibernate.event.EventListeners;
|
import org.hibernate.event.EventListeners;
|
||||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||||
import org.hibernate.loader.criteria.CriteriaLoader;
|
import org.hibernate.loader.criteria.CriteriaLoader;
|
||||||
|
@ -72,23 +64,42 @@ import org.hibernate.pretty.MessageHelper;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.util.CollectionHelper;
|
import org.hibernate.util.CollectionHelper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class StatelessSessionImpl extends AbstractSessionImpl
|
public class StatelessSessionImpl extends AbstractSessionImpl implements StatelessSession {
|
||||||
implements JDBCContext.Context, StatelessSession {
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger( StatelessSessionImpl.class );
|
private static final Logger log = LoggerFactory.getLogger( StatelessSessionImpl.class );
|
||||||
|
|
||||||
private JDBCContextImpl jdbcContext;
|
private TransactionCoordinator transactionCoordinator;
|
||||||
private PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this );
|
private PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this );
|
||||||
|
|
||||||
StatelessSessionImpl(Connection connection, SessionFactoryImpl factory) {
|
StatelessSessionImpl(Connection connection, SessionFactoryImpl factory) {
|
||||||
super( factory );
|
super( factory );
|
||||||
this.jdbcContext = new JDBCContextImpl( this, connection, EmptyInterceptor.INSTANCE );
|
this.transactionCoordinator = new TransactionCoordinatorImpl( connection, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TransactionContext ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionCoordinator getTransactionCoordinator() {
|
||||||
|
return transactionCoordinator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionEnvironment getTransactionEnvironment() {
|
||||||
|
return factory.getTransactionEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
// inserts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// inserts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -324,22 +335,33 @@ public class StatelessSessionImpl extends AbstractSessionImpl
|
||||||
if ( isClosed() ) {
|
if ( isClosed() ) {
|
||||||
throw new SessionException( "Session was already closed!" );
|
throw new SessionException( "Session was already closed!" );
|
||||||
}
|
}
|
||||||
jdbcContext.getConnectionManager().close();
|
transactionCoordinator.close();
|
||||||
setClosed();
|
setClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void managedFlush() {
|
public void managedFlush() {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
getJDBCContext().getConnectionManager().executeBatch();
|
getTransactionCoordinator().getJdbcCoordinator().executeBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldAutoClose() {
|
public boolean shouldAutoClose() {
|
||||||
return isAutoCloseSessionEnabled() && !isClosed();
|
return isAutoCloseSessionEnabled() && !isClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterTransactionCompletion(boolean successful, Transaction tx) {}
|
@Override
|
||||||
|
public void afterTransactionBegin(TransactionImplementor hibernateTransaction) {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
public void beforeTransactionCompletion(Transaction tx) {}
|
@Override
|
||||||
|
public void beforeTransactionCompletion(TransactionImplementor hibernateTransaction) {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTransactionCompletion(TransactionImplementor hibernateTransaction, boolean successful) {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
public String bestGuessEntityName(Object object) {
|
public String bestGuessEntityName(Object object) {
|
||||||
if (object instanceof HibernateProxy) {
|
if (object instanceof HibernateProxy) {
|
||||||
|
@ -350,7 +372,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public Connection connection() {
|
public Connection connection() {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
return jdbcContext.borrowConnection();
|
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getDistinctConnectionProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int executeUpdate(String query, QueryParameters queryParameters)
|
public int executeUpdate(String query, QueryParameters queryParameters)
|
||||||
|
@ -444,11 +466,11 @@ public class StatelessSessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return jdbcContext.getConnectionManager().isCurrentlyConnected();
|
return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTransactionInProgress() {
|
public boolean isTransactionInProgress() {
|
||||||
return jdbcContext.isTransactionInProgress();
|
return transactionCoordinator.isTransactionInProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAutoClear(boolean enabled) {
|
public void setAutoClear(boolean enabled) {
|
||||||
|
@ -465,7 +487,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public Transaction getTransaction() throws HibernateException {
|
public Transaction getTransaction() throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
return jdbcContext.getTransaction();
|
return transactionCoordinator.getTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transaction beginTransaction() throws HibernateException {
|
public Transaction beginTransaction() throws HibernateException {
|
||||||
|
@ -517,8 +539,8 @@ public class StatelessSessionImpl extends AbstractSessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterOperation(boolean success) {
|
public void afterOperation(boolean success) {
|
||||||
if ( !jdbcContext.isTransactionInProgress() ) {
|
if ( ! transactionCoordinator.isTransactionInProgress() ) {
|
||||||
jdbcContext.afterNontransactionalQuery(success);
|
transactionCoordinator.afterNonTransactionalQuery( success );;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,7 +641,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
CustomLoader loader = new CustomLoader( customQuery, getFactory() );
|
CustomLoader loader = new CustomLoader( customQuery, getFactory() );
|
||||||
return loader.scroll(queryParameters, this);
|
return loader.scroll( queryParameters, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
|
public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
|
||||||
|
@ -646,10 +668,6 @@ public class StatelessSessionImpl extends AbstractSessionImpl
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JDBCContext getJDBCContext() {
|
|
||||||
return jdbcContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoadQueryInfluencers getLoadQueryInfluencers() {
|
public LoadQueryInfluencers getLoadQueryInfluencers() {
|
||||||
return LoadQueryInfluencers.NONE;
|
return LoadQueryInfluencers.NONE;
|
||||||
}
|
}
|
||||||
|
@ -667,8 +685,6 @@ public class StatelessSessionImpl extends AbstractSessionImpl
|
||||||
|
|
||||||
public void setFetchProfile(String name) {}
|
public void setFetchProfile(String name) {}
|
||||||
|
|
||||||
public void afterTransactionBegin(Transaction tx) {}
|
|
||||||
|
|
||||||
protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
|
protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
|
||||||
// no auto-flushing to support in stateless session
|
// no auto-flushing to support in stateless session
|
||||||
return false;
|
return false;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue