added "flush()" method to TransactionStatus and TransactionSynchronization interfaces; test context manager automatically flushes transactions before rolling back; general polishing of transaction management code
This commit is contained in:
parent
dd7d299aa4
commit
4cc42bf16f
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -345,7 +345,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNewConnectionHolder() {
|
public boolean isNewConnectionHolder() {
|
||||||
return newConnectionHolder;
|
return this.newConnectionHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTransaction() {
|
public boolean hasTransaction() {
|
||||||
|
|
@ -357,7 +357,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMustRestoreAutoCommit() {
|
public boolean isMustRestoreAutoCommit() {
|
||||||
return mustRestoreAutoCommit;
|
return this.mustRestoreAutoCommit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRollbackOnly() {
|
public void setRollbackOnly() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -87,6 +87,10 @@ public abstract class JdbcTransactionObjectSupport implements SavepointManager,
|
||||||
return this.savepointAllowed;
|
return this.savepointAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Implementation of SavepointManager
|
// Implementation of SavepointManager
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -1958,6 +1958,9 @@ public class DataSourceTransactionManagerTests extends TestCase {
|
||||||
public void resume() {
|
public void resume() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
}
|
||||||
|
|
||||||
public void beforeCommit(boolean readOnly) {
|
public void beforeCommit(boolean readOnly) {
|
||||||
if (this.status != TransactionSynchronization.STATUS_COMMITTED) {
|
if (this.status != TransactionSynchronization.STATUS_COMMITTED) {
|
||||||
fail("Should never be called");
|
fail("Should never be called");
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -30,7 +30,6 @@ import javax.jms.TopicSession;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.transaction.support.ResourceHolder;
|
|
||||||
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
@ -387,7 +386,7 @@ public abstract class ConnectionFactoryUtils {
|
||||||
* (e.g. when participating in a JtaTransactionManager transaction).
|
* (e.g. when participating in a JtaTransactionManager transaction).
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||||
*/
|
*/
|
||||||
private static class JmsResourceSynchronization extends ResourceHolderSynchronization {
|
private static class JmsResourceSynchronization extends ResourceHolderSynchronization<JmsResourceHolder, Object> {
|
||||||
|
|
||||||
private final boolean transacted;
|
private final boolean transacted;
|
||||||
|
|
||||||
|
|
@ -400,17 +399,17 @@ public abstract class ConnectionFactoryUtils {
|
||||||
return !this.transacted;
|
return !this.transacted;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void processResourceAfterCommit(ResourceHolder resourceHolder) {
|
protected void processResourceAfterCommit(JmsResourceHolder resourceHolder) {
|
||||||
try {
|
try {
|
||||||
((JmsResourceHolder) resourceHolder).commitAll();
|
resourceHolder.commitAll();
|
||||||
}
|
}
|
||||||
catch (JMSException ex) {
|
catch (JMSException ex) {
|
||||||
throw new SynchedLocalTransactionFailedException("Local JMS transaction failed to commit", ex);
|
throw new SynchedLocalTransactionFailedException("Local JMS transaction failed to commit", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
|
protected void releaseResource(JmsResourceHolder resourceHolder, Object resourceKey) {
|
||||||
((JmsResourceHolder) resourceHolder).closeAll();
|
resourceHolder.closeAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -316,6 +316,10 @@ public class JmsTransactionManager extends AbstractPlatformTransactionManager
|
||||||
public boolean isRollbackOnly() {
|
public boolean isRollbackOnly() {
|
||||||
return this.resourceHolder.isRollbackOnly();
|
return this.resourceHolder.isRollbackOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -1160,21 +1160,20 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||||
/**
|
/**
|
||||||
* Check whether write operations are allowed on the given Session.
|
* Check whether write operations are allowed on the given Session.
|
||||||
* <p>Default implementation throws an InvalidDataAccessApiUsageException in
|
* <p>Default implementation throws an InvalidDataAccessApiUsageException in
|
||||||
* case of <code>FlushMode.NEVER/MANUAL</code>. Can be overridden in subclasses.
|
* case of <code>FlushMode.MANUAL</code>. Can be overridden in subclasses.
|
||||||
* @param session current Hibernate Session
|
* @param session current Hibernate Session
|
||||||
* @throws InvalidDataAccessApiUsageException if write operations are not allowed
|
* @throws InvalidDataAccessApiUsageException if write operations are not allowed
|
||||||
* @see #setCheckWriteOperations
|
* @see #setCheckWriteOperations
|
||||||
* @see #getFlushMode()
|
* @see #getFlushMode()
|
||||||
* @see #FLUSH_EAGER
|
* @see #FLUSH_EAGER
|
||||||
* @see org.hibernate.Session#getFlushMode()
|
* @see org.hibernate.Session#getFlushMode()
|
||||||
* @see org.hibernate.FlushMode#NEVER
|
|
||||||
* @see org.hibernate.FlushMode#MANUAL
|
* @see org.hibernate.FlushMode#MANUAL
|
||||||
*/
|
*/
|
||||||
protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
|
protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
|
||||||
if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&
|
if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&
|
||||||
session.getFlushMode().lessThan(FlushMode.COMMIT)) {
|
session.getFlushMode().lessThan(FlushMode.COMMIT)) {
|
||||||
throw new InvalidDataAccessApiUsageException(
|
throw new InvalidDataAccessApiUsageException(
|
||||||
"Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): "+
|
"Write operations are not allowed in read-only mode (FlushMode.MANUAL): "+
|
||||||
"Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");
|
"Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -828,7 +828,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||||
* Hibernate transaction object, representing a SessionHolder.
|
* Hibernate transaction object, representing a SessionHolder.
|
||||||
* Used as transaction object by HibernateTransactionManager.
|
* Used as transaction object by HibernateTransactionManager.
|
||||||
*/
|
*/
|
||||||
private static class HibernateTransactionObject extends JdbcTransactionObjectSupport {
|
private class HibernateTransactionObject extends JdbcTransactionObjectSupport {
|
||||||
|
|
||||||
private SessionHolder sessionHolder;
|
private SessionHolder sessionHolder;
|
||||||
|
|
||||||
|
|
@ -875,16 +875,25 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRollbackOnly() {
|
public void setRollbackOnly() {
|
||||||
getSessionHolder().setRollbackOnly();
|
this.sessionHolder.setRollbackOnly();
|
||||||
if (hasConnectionHolder()) {
|
if (hasConnectionHolder()) {
|
||||||
getConnectionHolder().setRollbackOnly();
|
getConnectionHolder().setRollbackOnly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRollbackOnly() {
|
public boolean isRollbackOnly() {
|
||||||
return getSessionHolder().isRollbackOnly() ||
|
return this.sessionHolder.isRollbackOnly() ||
|
||||||
(hasConnectionHolder() && getConnectionHolder().isRollbackOnly());
|
(hasConnectionHolder() && getConnectionHolder().isRollbackOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
try {
|
||||||
|
this.sessionHolder.getSession().flush();
|
||||||
|
}
|
||||||
|
catch (HibernateException ex) {
|
||||||
|
throw convertHibernateAccessException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -124,6 +124,16 @@ class SpringSessionSynchronization implements TransactionSynchronization, Ordere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
try {
|
||||||
|
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
|
||||||
|
getCurrentSession().flush();
|
||||||
|
}
|
||||||
|
catch (HibernateException ex) {
|
||||||
|
throw translateException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void beforeCommit(boolean readOnly) throws DataAccessException {
|
public void beforeCommit(boolean readOnly) throws DataAccessException {
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
Session session = getCurrentSession();
|
Session session = getCurrentSession();
|
||||||
|
|
@ -135,17 +145,21 @@ class SpringSessionSynchronization implements TransactionSynchronization, Ordere
|
||||||
session.flush();
|
session.flush();
|
||||||
}
|
}
|
||||||
catch (HibernateException ex) {
|
catch (HibernateException ex) {
|
||||||
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
|
throw translateException(ex);
|
||||||
JDBCException jdbcEx = (JDBCException) ex;
|
|
||||||
throw this.jdbcExceptionTranslator.translate(
|
|
||||||
"Hibernate flushing: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
|
|
||||||
}
|
|
||||||
throw SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataAccessException translateException(HibernateException ex) {
|
||||||
|
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
|
||||||
|
JDBCException jdbcEx = (JDBCException) ex;
|
||||||
|
return this.jdbcExceptionTranslator.translate(
|
||||||
|
"Hibernate flushing: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
|
||||||
|
}
|
||||||
|
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
public void beforeCompletion() {
|
public void beforeCompletion() {
|
||||||
if (this.jtaTransaction != null) {
|
if (this.jtaTransaction != null) {
|
||||||
// Typically in case of a suspended JTA transaction:
|
// Typically in case of a suspended JTA transaction:
|
||||||
|
|
|
||||||
|
|
@ -144,10 +144,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
* {@link org.hibernate.Session}. Only applied in single session mode.
|
* {@link org.hibernate.Session}. Only applied in single session mode.
|
||||||
* <p>Can be populated with the corresponding constant name in XML bean
|
* <p>Can be populated with the corresponding constant name in XML bean
|
||||||
* definitions: e.g. "AUTO".
|
* definitions: e.g. "AUTO".
|
||||||
* <p>The default is "NEVER". Specify "AUTO" if you intend to use
|
* <p>The default is "MANUAL". Specify "AUTO" if you intend to use
|
||||||
* this filter without service layer transactions.
|
* this filter without service layer transactions.
|
||||||
* @see org.hibernate.Session#setFlushMode
|
* @see org.hibernate.Session#setFlushMode
|
||||||
* @see org.hibernate.FlushMode#NEVER
|
* @see org.hibernate.FlushMode#MANUAL
|
||||||
* @see org.hibernate.FlushMode#AUTO
|
* @see org.hibernate.FlushMode#AUTO
|
||||||
*/
|
*/
|
||||||
public void setFlushMode(FlushMode flushMode) {
|
public void setFlushMode(FlushMode flushMode) {
|
||||||
|
|
@ -247,14 +247,14 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
* Note that this just applies in single session mode!
|
* Note that this just applies in single session mode!
|
||||||
* <p>The default implementation delegates to the
|
* <p>The default implementation delegates to the
|
||||||
* <code>SessionFactoryUtils.getSession</code> method and
|
* <code>SessionFactoryUtils.getSession</code> method and
|
||||||
* sets the <code>Session</code>'s flush mode to "NEVER".
|
* sets the <code>Session</code>'s flush mode to "MANUAL".
|
||||||
* <p>Can be overridden in subclasses for creating a Session with a
|
* <p>Can be overridden in subclasses for creating a Session with a
|
||||||
* custom entity interceptor or JDBC exception translator.
|
* custom entity interceptor or JDBC exception translator.
|
||||||
* @param sessionFactory the SessionFactory that this filter uses
|
* @param sessionFactory the SessionFactory that this filter uses
|
||||||
* @return the Session to use
|
* @return the Session to use
|
||||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
* @throws DataAccessResourceFailureException if the Session could not be created
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
|
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
|
||||||
* @see org.hibernate.FlushMode#NEVER
|
* @see org.hibernate.FlushMode#MANUAL
|
||||||
*/
|
*/
|
||||||
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
|
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
|
||||||
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
|
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -503,7 +503,7 @@ public class JdoTransactionManager extends AbstractPlatformTransactionManager
|
||||||
/**
|
/**
|
||||||
* Convert the given JDOException to an appropriate exception from the
|
* Convert the given JDOException to an appropriate exception from the
|
||||||
* <code>org.springframework.dao</code> hierarchy.
|
* <code>org.springframework.dao</code> hierarchy.
|
||||||
* <p>Default implementation delegates to the JdoDialect.
|
* <p>The default implementation delegates to the JdoDialect.
|
||||||
* May be overridden in subclasses.
|
* May be overridden in subclasses.
|
||||||
* @param ex JDOException that occured
|
* @param ex JDOException that occured
|
||||||
* @return the corresponding DataAccessException instance
|
* @return the corresponding DataAccessException instance
|
||||||
|
|
@ -518,7 +518,7 @@ public class JdoTransactionManager extends AbstractPlatformTransactionManager
|
||||||
* JDO transaction object, representing a PersistenceManagerHolder.
|
* JDO transaction object, representing a PersistenceManagerHolder.
|
||||||
* Used as transaction object by JdoTransactionManager.
|
* Used as transaction object by JdoTransactionManager.
|
||||||
*/
|
*/
|
||||||
private static class JdoTransactionObject extends JdbcTransactionObjectSupport {
|
private class JdoTransactionObject extends JdbcTransactionObjectSupport {
|
||||||
|
|
||||||
private PersistenceManagerHolder persistenceManagerHolder;
|
private PersistenceManagerHolder persistenceManagerHolder;
|
||||||
|
|
||||||
|
|
@ -533,11 +533,11 @@ public class JdoTransactionManager extends AbstractPlatformTransactionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
public PersistenceManagerHolder getPersistenceManagerHolder() {
|
public PersistenceManagerHolder getPersistenceManagerHolder() {
|
||||||
return persistenceManagerHolder;
|
return this.persistenceManagerHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNewPersistenceManagerHolder() {
|
public boolean isNewPersistenceManagerHolder() {
|
||||||
return newPersistenceManagerHolder;
|
return this.newPersistenceManagerHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTransaction() {
|
public boolean hasTransaction() {
|
||||||
|
|
@ -550,7 +550,7 @@ public class JdoTransactionManager extends AbstractPlatformTransactionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getTransactionData() {
|
public Object getTransactionData() {
|
||||||
return transactionData;
|
return this.transactionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRollbackOnly() {
|
public void setRollbackOnly() {
|
||||||
|
|
@ -567,6 +567,15 @@ public class JdoTransactionManager extends AbstractPlatformTransactionManager
|
||||||
Transaction tx = this.persistenceManagerHolder.getPersistenceManager().currentTransaction();
|
Transaction tx = this.persistenceManagerHolder.getPersistenceManager().currentTransaction();
|
||||||
return tx.getRollbackOnly();
|
return tx.getRollbackOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
try {
|
||||||
|
this.persistenceManagerHolder.getPersistenceManager().flush();
|
||||||
|
}
|
||||||
|
catch (JDOException ex) {
|
||||||
|
throw convertJdoAccessException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||||
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
|
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
|
||||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
||||||
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
|
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
|
||||||
import org.springframework.transaction.support.ResourceHolder;
|
|
||||||
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
@ -293,7 +292,8 @@ public abstract class PersistenceManagerFactoryUtils {
|
||||||
* (e.g. when participating in a JtaTransactionManager transaction).
|
* (e.g. when participating in a JtaTransactionManager transaction).
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||||
*/
|
*/
|
||||||
private static class PersistenceManagerSynchronization extends ResourceHolderSynchronization
|
private static class PersistenceManagerSynchronization
|
||||||
|
extends ResourceHolderSynchronization<PersistenceManagerHolder, PersistenceManagerFactory>
|
||||||
implements Ordered {
|
implements Ordered {
|
||||||
|
|
||||||
private final boolean newPersistenceManager;
|
private final boolean newPersistenceManager;
|
||||||
|
|
@ -308,15 +308,24 @@ public abstract class PersistenceManagerFactoryUtils {
|
||||||
return PERSISTENCE_MANAGER_SYNCHRONIZATION_ORDER;
|
return PERSISTENCE_MANAGER_SYNCHRONIZATION_ORDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flushResource(PersistenceManagerHolder resourceHolder) {
|
||||||
|
try {
|
||||||
|
resourceHolder.getPersistenceManager().flush();
|
||||||
|
}
|
||||||
|
catch (JDOException ex) {
|
||||||
|
throw convertJdoAccessException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldUnbindAtCompletion() {
|
protected boolean shouldUnbindAtCompletion() {
|
||||||
return this.newPersistenceManager;
|
return this.newPersistenceManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
|
protected void releaseResource(PersistenceManagerHolder resourceHolder, PersistenceManagerFactory resourceKey) {
|
||||||
releasePersistenceManager(((PersistenceManagerHolder) resourceHolder).getPersistenceManager(),
|
releasePersistenceManager(resourceHolder.getPersistenceManager(), resourceKey);
|
||||||
(PersistenceManagerFactory) resourceKey);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -105,7 +105,7 @@ public abstract class EntityManagerFactoryUtils {
|
||||||
}
|
}
|
||||||
// No matching persistence unit found - simply take the EntityManagerFactory
|
// No matching persistence unit found - simply take the EntityManagerFactory
|
||||||
// with the persistence unit name as bean name (by convention).
|
// with the persistence unit name as bean name (by convention).
|
||||||
return (EntityManagerFactory) beanFactory.getBean(unitName, EntityManagerFactory.class);
|
return beanFactory.getBean(unitName, EntityManagerFactory.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -345,41 +345,62 @@ public abstract class EntityManagerFactoryUtils {
|
||||||
* (e.g. when participating in a JtaTransactionManager transaction).
|
* (e.g. when participating in a JtaTransactionManager transaction).
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||||
*/
|
*/
|
||||||
private static class EntityManagerSynchronization extends ResourceHolderSynchronization implements Ordered {
|
private static class EntityManagerSynchronization
|
||||||
|
extends ResourceHolderSynchronization<EntityManagerHolder, EntityManagerFactory>
|
||||||
|
implements Ordered {
|
||||||
|
|
||||||
private final Object transactionData;
|
private final Object transactionData;
|
||||||
|
|
||||||
|
private final JpaDialect jpaDialect;
|
||||||
|
|
||||||
private final boolean newEntityManager;
|
private final boolean newEntityManager;
|
||||||
|
|
||||||
public EntityManagerSynchronization(
|
public EntityManagerSynchronization(
|
||||||
EntityManagerHolder emHolder, EntityManagerFactory emf, Object transactionData, boolean newEntityManager) {
|
EntityManagerHolder emHolder, EntityManagerFactory emf, Object txData, boolean newEm) {
|
||||||
super(emHolder, emf);
|
super(emHolder, emf);
|
||||||
this.transactionData = transactionData;
|
this.transactionData = txData;
|
||||||
this.newEntityManager = newEntityManager;
|
this.jpaDialect = (emf instanceof EntityManagerFactoryInfo ?
|
||||||
|
((EntityManagerFactoryInfo) emf).getJpaDialect() : null);
|
||||||
|
this.newEntityManager = newEm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOrder() {
|
public int getOrder() {
|
||||||
return ENTITY_MANAGER_SYNCHRONIZATION_ORDER;
|
return ENTITY_MANAGER_SYNCHRONIZATION_ORDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void flushResource(EntityManagerHolder resourceHolder) {
|
||||||
|
try {
|
||||||
|
resourceHolder.getEntityManager().flush();
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex) {
|
||||||
|
if (this.jpaDialect != null) {
|
||||||
|
throw this.jpaDialect.translateExceptionIfPossible(ex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw convertJpaAccessExceptionIfPossible(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldUnbindAtCompletion() {
|
protected boolean shouldUnbindAtCompletion() {
|
||||||
return this.newEntityManager;
|
return this.newEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
|
protected void releaseResource(EntityManagerHolder resourceHolder, EntityManagerFactory resourceKey) {
|
||||||
closeEntityManager(((EntityManagerHolder) resourceHolder).getEntityManager());
|
closeEntityManager(resourceHolder.getEntityManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void cleanupResource(ResourceHolder resourceHolder, Object resourceKey, boolean committed) {
|
protected void cleanupResource(EntityManagerHolder resourceHolder, EntityManagerFactory resourceKey, boolean committed) {
|
||||||
if (!committed) {
|
if (!committed) {
|
||||||
// Clear all pending inserts/updates/deletes in the EntityManager.
|
// Clear all pending inserts/updates/deletes in the EntityManager.
|
||||||
// Necessary for pre-bound EntityManagers, to avoid inconsistent state.
|
// Necessary for pre-bound EntityManagers, to avoid inconsistent state.
|
||||||
((EntityManagerHolder) resourceHolder).getEntityManager().clear();
|
resourceHolder.getEntityManager().clear();
|
||||||
}
|
}
|
||||||
cleanupTransaction(this.transactionData, (EntityManagerFactory) resourceKey);
|
cleanupTransaction(this.transactionData, resourceKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,8 @@ public abstract class ExtendedEntityManagerCreator {
|
||||||
* TransactionSynchronization enlisting an extended EntityManager
|
* TransactionSynchronization enlisting an extended EntityManager
|
||||||
* with a current Spring transaction.
|
* with a current Spring transaction.
|
||||||
*/
|
*/
|
||||||
private static class ExtendedEntityManagerSynchronization extends ResourceHolderSynchronization
|
private static class ExtendedEntityManagerSynchronization
|
||||||
|
extends ResourceHolderSynchronization<EntityManagerHolder, EntityManager>
|
||||||
implements Ordered {
|
implements Ordered {
|
||||||
|
|
||||||
private final EntityManager entityManager;
|
private final EntityManager entityManager;
|
||||||
|
|
@ -454,6 +455,16 @@ public abstract class ExtendedEntityManagerCreator {
|
||||||
return EntityManagerFactoryUtils.ENTITY_MANAGER_SYNCHRONIZATION_ORDER + 1;
|
return EntityManagerFactoryUtils.ENTITY_MANAGER_SYNCHRONIZATION_ORDER + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void flushResource(EntityManagerHolder resourceHolder) {
|
||||||
|
try {
|
||||||
|
this.entityManager.flush();
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex) {
|
||||||
|
throw convertException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldReleaseBeforeCompletion() {
|
protected boolean shouldReleaseBeforeCompletion() {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -467,7 +478,7 @@ public abstract class ExtendedEntityManagerCreator {
|
||||||
this.entityManager.getTransaction().commit();
|
this.entityManager.getTransaction().commit();
|
||||||
}
|
}
|
||||||
catch (RuntimeException ex) {
|
catch (RuntimeException ex) {
|
||||||
throw convertCompletionException(ex);
|
throw convertException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -480,12 +491,12 @@ public abstract class ExtendedEntityManagerCreator {
|
||||||
this.entityManager.getTransaction().rollback();
|
this.entityManager.getTransaction().rollback();
|
||||||
}
|
}
|
||||||
catch (RuntimeException ex) {
|
catch (RuntimeException ex) {
|
||||||
throw convertCompletionException(ex);
|
throw convertException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RuntimeException convertCompletionException(RuntimeException ex) {
|
private RuntimeException convertException(RuntimeException ex) {
|
||||||
DataAccessException daex = (this.exceptionTranslator != null) ?
|
DataAccessException daex = (this.exceptionTranslator != null) ?
|
||||||
this.exceptionTranslator.translateExceptionIfPossible(ex) :
|
this.exceptionTranslator.translateExceptionIfPossible(ex) :
|
||||||
EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex);
|
EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -19,7 +19,6 @@ package org.springframework.orm.jpa;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
import javax.persistence.EntityTransaction;
|
import javax.persistence.EntityTransaction;
|
||||||
|
|
@ -553,7 +552,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
||||||
* JPA transaction object, representing a EntityManagerHolder.
|
* JPA transaction object, representing a EntityManagerHolder.
|
||||||
* Used as transaction object by JpaTransactionManager.
|
* Used as transaction object by JpaTransactionManager.
|
||||||
*/
|
*/
|
||||||
private static class JpaTransactionObject extends JdbcTransactionObjectSupport {
|
private class JpaTransactionObject extends JdbcTransactionObjectSupport {
|
||||||
|
|
||||||
private EntityManagerHolder entityManagerHolder;
|
private EntityManagerHolder entityManagerHolder;
|
||||||
|
|
||||||
|
|
@ -606,6 +605,15 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
||||||
return tx.getRollbackOnly();
|
return tx.getRollbackOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
try {
|
||||||
|
this.entityManagerHolder.getEntityManager().flush();
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex) {
|
||||||
|
throw DataAccessUtils.translateIfNecessary(ex, getJpaDialect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object createSavepoint() throws TransactionException {
|
public Object createSavepoint() throws TransactionException {
|
||||||
return getSavepointManager().createSavepoint();
|
return getSavepointManager().createSavepoint();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -18,7 +18,6 @@ package org.springframework.orm.hibernate3;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.transaction.RollbackException;
|
import javax.transaction.RollbackException;
|
||||||
import javax.transaction.Status;
|
import javax.transaction.Status;
|
||||||
import javax.transaction.Synchronization;
|
import javax.transaction.Synchronization;
|
||||||
|
|
@ -108,7 +107,7 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
session.createQuery("some query string");
|
session.createQuery("some query string");
|
||||||
sessionControl.setReturnValue(query, 1);
|
sessionControl.setReturnValue(query, 1);
|
||||||
if (readOnly) {
|
if (readOnly) {
|
||||||
session.setFlushMode(FlushMode.NEVER);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
}
|
}
|
||||||
query.list();
|
query.list();
|
||||||
|
|
@ -370,6 +369,14 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testJtaTransactionRollback() throws Exception {
|
public void testJtaTransactionRollback() throws Exception {
|
||||||
|
doTestJtaTransactionRollback(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testJtaTransactionRollbackWithFlush() throws Exception {
|
||||||
|
doTestJtaTransactionRollback(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestJtaTransactionRollback(final boolean flush) throws Exception {
|
||||||
MockControl utControl = MockControl.createControl(UserTransaction.class);
|
MockControl utControl = MockControl.createControl(UserTransaction.class);
|
||||||
UserTransaction ut = (UserTransaction) utControl.getMock();
|
UserTransaction ut = (UserTransaction) utControl.getMock();
|
||||||
ut.getStatus();
|
ut.getStatus();
|
||||||
|
|
@ -390,6 +397,10 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
sfControl.setReturnValue(session, 1);
|
sfControl.setReturnValue(session, 1);
|
||||||
session.getSessionFactory();
|
session.getSessionFactory();
|
||||||
sessionControl.setReturnValue(sf, 1);
|
sessionControl.setReturnValue(sf, 1);
|
||||||
|
if (flush) {
|
||||||
|
session.flush();
|
||||||
|
sessionControl.setVoidCallable(1);
|
||||||
|
}
|
||||||
sfControl.replay();
|
sfControl.replay();
|
||||||
sessionControl.replay();
|
sessionControl.replay();
|
||||||
|
|
||||||
|
|
@ -409,6 +420,9 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (flush) {
|
||||||
|
status.flush();
|
||||||
|
}
|
||||||
status.setRollbackOnly();
|
status.setRollbackOnly();
|
||||||
sessionControl.verify();
|
sessionControl.verify();
|
||||||
sessionControl.reset();
|
sessionControl.reset();
|
||||||
|
|
@ -495,7 +509,7 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
sessionControl.setReturnValue(true, 5);
|
sessionControl.setReturnValue(true, 5);
|
||||||
session.getFlushMode();
|
session.getFlushMode();
|
||||||
if (flushNever) {
|
if (flushNever) {
|
||||||
sessionControl.setReturnValue(FlushMode.NEVER, 1);
|
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
session.setFlushMode(FlushMode.AUTO);
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
|
|
@ -546,7 +560,7 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
session.flush();
|
session.flush();
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
if (flushNever) {
|
if (flushNever) {
|
||||||
session.setFlushMode(FlushMode.NEVER);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1064,15 +1078,15 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
session.getSessionFactory();
|
session.getSessionFactory();
|
||||||
sessionControl.setReturnValue(sf, 1);
|
sessionControl.setReturnValue(sf, 1);
|
||||||
session.getFlushMode();
|
session.getFlushMode();
|
||||||
sessionControl.setReturnValue(FlushMode.NEVER, 1);
|
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
session.setFlushMode(FlushMode.AUTO);
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
session.flush();
|
session.flush();
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
session.setFlushMode(FlushMode.NEVER);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
session.getFlushMode();
|
session.getFlushMode();
|
||||||
sessionControl.setReturnValue(FlushMode.NEVER, 1);
|
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
||||||
session.close();
|
session.close();
|
||||||
sessionControl.setReturnValue(null, 1);
|
sessionControl.setReturnValue(null, 1);
|
||||||
sfControl.replay();
|
sfControl.replay();
|
||||||
|
|
@ -1306,7 +1320,7 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
sfControl.setReturnValue(tm, 7);
|
sfControl.setReturnValue(tm, 7);
|
||||||
session.isOpen();
|
session.isOpen();
|
||||||
sessionControl.setReturnValue(true, 8);
|
sessionControl.setReturnValue(true, 8);
|
||||||
session.setFlushMode(FlushMode.NEVER);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
session.close();
|
session.close();
|
||||||
sessionControl.setReturnValue(null, 2);
|
sessionControl.setReturnValue(null, 2);
|
||||||
|
|
@ -1667,7 +1681,7 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
sessionControl.setReturnValue(true, 5);
|
sessionControl.setReturnValue(true, 5);
|
||||||
session.getFlushMode();
|
session.getFlushMode();
|
||||||
if (flushNever) {
|
if (flushNever) {
|
||||||
sessionControl.setReturnValue(FlushMode.NEVER, 1);
|
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
session.setFlushMode(FlushMode.AUTO);
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
}
|
}
|
||||||
|
|
@ -1702,7 +1716,7 @@ public class HibernateJtaTransactionTests extends TestCase {
|
||||||
session.flush();
|
session.flush();
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
if (flushNever) {
|
if (flushNever) {
|
||||||
session.setFlushMode(FlushMode.NEVER);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
sessionControl.setVoidCallable(1);
|
||||||
}
|
}
|
||||||
session.disconnect();
|
session.disconnect();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -1779,6 +1779,51 @@ public class HibernateTransactionManagerTests extends TestCase {
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
|
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testTransactionFlush() throws Exception {
|
||||||
|
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
||||||
|
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
||||||
|
MockControl sessionControl = MockControl.createControl(Session.class);
|
||||||
|
final Session session = (Session) sessionControl.getMock();
|
||||||
|
MockControl txControl = MockControl.createControl(Transaction.class);
|
||||||
|
Transaction tx = (Transaction) txControl.getMock();
|
||||||
|
|
||||||
|
sf.openSession();
|
||||||
|
sfControl.setReturnValue(session, 1);
|
||||||
|
session.beginTransaction();
|
||||||
|
sessionControl.setReturnValue(tx, 1);
|
||||||
|
session.flush();
|
||||||
|
sessionControl.setVoidCallable(1);
|
||||||
|
tx.commit();
|
||||||
|
txControl.setVoidCallable(1);
|
||||||
|
session.close();
|
||||||
|
sessionControl.setReturnValue(null, 1);
|
||||||
|
|
||||||
|
sfControl.replay();
|
||||||
|
sessionControl.replay();
|
||||||
|
txControl.replay();
|
||||||
|
|
||||||
|
HibernateTransactionManager tm = new HibernateTransactionManager(sf);
|
||||||
|
tm.setPrepareConnection(false);
|
||||||
|
TransactionTemplate tt = new TransactionTemplate(tm);
|
||||||
|
assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
|
||||||
|
|
||||||
|
tt.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
|
||||||
|
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
|
||||||
|
status.flush();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
|
||||||
|
sfControl.verify();
|
||||||
|
sessionControl.verify();
|
||||||
|
txControl.verify();
|
||||||
|
}
|
||||||
|
|
||||||
protected void tearDown() {
|
protected void tearDown() {
|
||||||
assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
|
assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
|
||||||
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
|
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -1222,4 +1222,41 @@ public class JdoTransactionManagerTests extends TestCase {
|
||||||
queryControl.verify();
|
queryControl.verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testTransactionFlush() {
|
||||||
|
pmf.getConnectionFactory();
|
||||||
|
pmfControl.setReturnValue(null, 1);
|
||||||
|
pmf.getPersistenceManager();
|
||||||
|
pmfControl.setReturnValue(pm, 1);
|
||||||
|
pm.currentTransaction();
|
||||||
|
pmControl.setReturnValue(tx, 3);
|
||||||
|
pm.flush();
|
||||||
|
pmControl.setVoidCallable(1);
|
||||||
|
pm.close();
|
||||||
|
pmControl.setVoidCallable(1);
|
||||||
|
tx.begin();
|
||||||
|
txControl.setVoidCallable(1);
|
||||||
|
tx.getRollbackOnly();
|
||||||
|
txControl.setReturnValue(false, 1);
|
||||||
|
tx.commit();
|
||||||
|
txControl.setVoidCallable(1);
|
||||||
|
pmfControl.replay();
|
||||||
|
pmControl.replay();
|
||||||
|
txControl.replay();
|
||||||
|
|
||||||
|
PlatformTransactionManager tm = new JdoTransactionManager(pmf);
|
||||||
|
TransactionTemplate tt = new TransactionTemplate(tm);
|
||||||
|
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf));
|
||||||
|
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
|
||||||
|
|
||||||
|
tt.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf));
|
||||||
|
status.flush();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf));
|
||||||
|
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -18,7 +18,6 @@ package org.springframework.orm.jpa;
|
||||||
|
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.EntityNotFoundException;
|
import javax.persistence.EntityNotFoundException;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
|
|
@ -95,9 +94,8 @@ public abstract class AbstractContainerEntityManagerFactoryIntegrationTests
|
||||||
Person notThere = sharedEntityManager.getReference(Person.class, 666);
|
Person notThere = sharedEntityManager.getReference(Person.class, 666);
|
||||||
|
|
||||||
// We may get here (as with Hibernate).
|
// We may get here (as with Hibernate).
|
||||||
// Either behaviour is
|
// Either behaviour is valid: throw exception on first access
|
||||||
// valid--throw exception on first access
|
// or on getReference itself.
|
||||||
// or on getReference itself
|
|
||||||
notThere.getFirstName();
|
notThere.getFirstName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,8 +173,7 @@ public abstract class AbstractContainerEntityManagerFactoryIntegrationTests
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void testInstantiateAndSave(EntityManager em) {
|
protected void testInstantiateAndSave(EntityManager em) {
|
||||||
assertEquals("Should be no people from previous transactions",
|
assertEquals("Should be no people from previous transactions", 0, countRowsInTable("person"));
|
||||||
0, countRowsInTable("person"));
|
|
||||||
Person p = new Person();
|
Person p = new Person();
|
||||||
p.setFirstName("Tony");
|
p.setFirstName("Tony");
|
||||||
p.setLastName("Blair");
|
p.setLastName("Blair");
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2006 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -93,13 +93,11 @@ public class ApplicationManagedEntityManagerIntegrationTests extends AbstractEnt
|
||||||
em.persist(p);
|
em.persist(p);
|
||||||
|
|
||||||
em.flush();
|
em.flush();
|
||||||
assertEquals("1 row must have been inserted",
|
assertEquals("1 row must have been inserted", 1, countRowsInTable("person"));
|
||||||
1, countRowsInTable("person"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testStateClean() {
|
public void testStateClean() {
|
||||||
assertEquals("Should be no people from previous transactions",
|
assertEquals("Should be no people from previous transactions", 0, countRowsInTable("person"));
|
||||||
0, countRowsInTable("person"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReuseInNewTransaction() {
|
public void testReuseInNewTransaction() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2006 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -114,8 +114,7 @@ public class ContainerManagedEntityManagerIntegrationTests extends AbstractEntit
|
||||||
em.persist(p);
|
em.persist(p);
|
||||||
|
|
||||||
em.flush();
|
em.flush();
|
||||||
assertEquals("1 row must have been inserted",
|
assertEquals("1 row must have been inserted", 1, countRowsInTable("person"));
|
||||||
1, countRowsInTable("person"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReuseInNewTransaction() {
|
public void testReuseInNewTransaction() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -1071,4 +1071,33 @@ public class JpaTransactionManagerTests extends TestCase {
|
||||||
txControl.verify();
|
txControl.verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testTransactionFlush() {
|
||||||
|
managerControl.expectAndReturn(manager.getTransaction(), tx);
|
||||||
|
txControl.expectAndReturn(tx.getRollbackOnly(), false);
|
||||||
|
managerControl.expectAndReturn(manager.getTransaction(), tx);
|
||||||
|
tx.commit();
|
||||||
|
manager.flush();
|
||||||
|
|
||||||
|
factoryControl.replay();
|
||||||
|
managerControl.replay();
|
||||||
|
txControl.replay();
|
||||||
|
|
||||||
|
assertTrue(!TransactionSynchronizationManager.hasResource(factory));
|
||||||
|
assertTrue(!TransactionSynchronizationManager.isSynchronizationActive());
|
||||||
|
|
||||||
|
tt.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
assertTrue(TransactionSynchronizationManager.hasResource(factory));
|
||||||
|
status.flush();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(!TransactionSynchronizationManager.hasResource(factory));
|
||||||
|
assertTrue(!TransactionSynchronizationManager.isSynchronizationActive());
|
||||||
|
|
||||||
|
factoryControl.verify();
|
||||||
|
managerControl.verify();
|
||||||
|
txControl.verify();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -335,15 +335,15 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||||
if (rollbackAnnotation != null) {
|
if (rollbackAnnotation != null) {
|
||||||
boolean rollbackOverride = rollbackAnnotation.value();
|
boolean rollbackOverride = rollbackAnnotation.value();
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Method-level @Rollback(" + rollbackOverride + ") overrides default rollback [" + rollback
|
logger.debug("Method-level @Rollback(" + rollbackOverride + ") overrides default rollback [" +
|
||||||
+ "] for test context [" + testContext + "]");
|
rollback + "] for test context [" + testContext + "]");
|
||||||
}
|
}
|
||||||
rollback = rollbackOverride;
|
rollback = rollbackOverride;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("No method-level @Rollback override: using default rollback [" + rollback
|
logger.debug("No method-level @Rollback override: using default rollback [" +
|
||||||
+ "] for test context [" + testContext + "]");
|
rollback + "] for test context [" + testContext + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rollback;
|
return rollback;
|
||||||
|
|
@ -498,6 +498,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||||
|
|
||||||
public void endTransaction(boolean rollback) {
|
public void endTransaction(boolean rollback) {
|
||||||
if (rollback) {
|
if (rollback) {
|
||||||
|
this.transactionStatus.flush();
|
||||||
this.transactionManager.rollback(this.transactionStatus);
|
this.transactionManager.rollback(this.transactionStatus);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -25,7 +25,6 @@ import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.jca.cci.CannotGetCciConnectionException;
|
import org.springframework.jca.cci.CannotGetCciConnectionException;
|
||||||
import org.springframework.transaction.support.ResourceHolder;
|
|
||||||
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
@ -199,15 +198,16 @@ public abstract class ConnectionFactoryUtils {
|
||||||
* Callback for resource cleanup at the end of a non-native CCI transaction
|
* Callback for resource cleanup at the end of a non-native CCI transaction
|
||||||
* (e.g. when participating in a JTA transaction).
|
* (e.g. when participating in a JTA transaction).
|
||||||
*/
|
*/
|
||||||
private static class ConnectionSynchronization extends ResourceHolderSynchronization {
|
private static class ConnectionSynchronization
|
||||||
|
extends ResourceHolderSynchronization<ConnectionHolder, ConnectionFactory> {
|
||||||
|
|
||||||
public ConnectionSynchronization(ConnectionHolder connectionHolder, ConnectionFactory connectionFactory) {
|
public ConnectionSynchronization(ConnectionHolder connectionHolder, ConnectionFactory connectionFactory) {
|
||||||
super(connectionHolder, connectionFactory);
|
super(connectionHolder, connectionFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
|
protected void releaseResource(ConnectionHolder resourceHolder, ConnectionFactory resourceKey) {
|
||||||
releaseConnection(((ConnectionHolder) resourceHolder).getConnection(), (ConnectionFactory) resourceKey);
|
releaseConnection(resourceHolder.getConnection(), resourceKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -75,6 +75,12 @@ public interface TransactionStatus extends SavepointManager {
|
||||||
*/
|
*/
|
||||||
boolean isRollbackOnly();
|
boolean isRollbackOnly();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush the underlying session to the datastore, if applicable:
|
||||||
|
* for example, all affected Hibernate/JPA sessions.
|
||||||
|
*/
|
||||||
|
void flush();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether this transaction is completed, that is,
|
* Return whether this transaction is completed, that is,
|
||||||
* whether it has already been committed or rolled back.
|
* whether it has already been committed or rolled back.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -22,6 +22,7 @@ import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
import org.springframework.transaction.TransactionSystemException;
|
import org.springframework.transaction.TransactionSystemException;
|
||||||
import org.springframework.transaction.support.SmartTransactionObject;
|
import org.springframework.transaction.support.SmartTransactionObject;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JTA transaction object, representing a {@link javax.transaction.UserTransaction}.
|
* JTA transaction object, representing a {@link javax.transaction.UserTransaction}.
|
||||||
|
|
@ -72,4 +73,13 @@ public class JtaTransactionObject implements SmartTransactionObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation triggers flush callbacks,
|
||||||
|
* assuming that they will flush all affected ORM sessions.
|
||||||
|
* @see org.springframework.transaction.support.TransactionSynchronization#flush()
|
||||||
|
*/
|
||||||
|
public void flush() {
|
||||||
|
TransactionSynchronizationUtils.triggerFlush();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -89,6 +89,12 @@ public abstract class AbstractTransactionStatus implements TransactionStatus {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementations is empty, considering flush as a no-op.
|
||||||
|
*/
|
||||||
|
public void flush() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark this transaction as completed, that is, committed or rolled back.
|
* Mark this transaction as completed, that is, committed or rolled back.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -145,7 +145,7 @@ public class DefaultTransactionStatus extends AbstractTransactionStatus {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the rollback-only flag via checking both the transaction object,
|
* Determine the rollback-only flag via checking both the transaction object,
|
||||||
* provided that the latter implements the SmartTransactionObject interface.
|
* provided that the latter implements the {@link SmartTransactionObject} interface.
|
||||||
* <p>Will return "true" if the transaction itself has been marked rollback-only
|
* <p>Will return "true" if the transaction itself has been marked rollback-only
|
||||||
* by the transaction coordinator, for example in case of a timeout.
|
* by the transaction coordinator, for example in case of a timeout.
|
||||||
* @see SmartTransactionObject#isRollbackOnly
|
* @see SmartTransactionObject#isRollbackOnly
|
||||||
|
|
@ -156,6 +156,16 @@ public class DefaultTransactionStatus extends AbstractTransactionStatus {
|
||||||
((SmartTransactionObject) this.transaction).isRollbackOnly());
|
((SmartTransactionObject) this.transaction).isRollbackOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate the flushing to the transaction object,
|
||||||
|
* provided that the latter implements the {@link SmartTransactionObject} interface.
|
||||||
|
*/
|
||||||
|
public void flush() {
|
||||||
|
if (this.transaction instanceof SmartTransactionObject) {
|
||||||
|
((SmartTransactionObject) this.transaction).flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This implementation exposes the SavepointManager interface
|
* This implementation exposes the SavepointManager interface
|
||||||
* of the underlying transaction object, if any.
|
* of the underlying transaction object, if any.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -23,11 +23,12 @@ package org.springframework.transaction.support;
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 2.5.5
|
* @since 2.5.5
|
||||||
*/
|
*/
|
||||||
public class ResourceHolderSynchronization implements TransactionSynchronization {
|
public abstract class ResourceHolderSynchronization<H extends ResourceHolder, K>
|
||||||
|
implements TransactionSynchronization {
|
||||||
|
|
||||||
private final ResourceHolder resourceHolder;
|
private final H resourceHolder;
|
||||||
|
|
||||||
private final Object resourceKey;
|
private final K resourceKey;
|
||||||
|
|
||||||
private volatile boolean holderActive = true;
|
private volatile boolean holderActive = true;
|
||||||
|
|
||||||
|
|
@ -38,7 +39,7 @@ public class ResourceHolderSynchronization implements TransactionSynchronization
|
||||||
* @param resourceKey the key to bind the ResourceHolder for
|
* @param resourceKey the key to bind the ResourceHolder for
|
||||||
* @see TransactionSynchronizationManager#bindResource
|
* @see TransactionSynchronizationManager#bindResource
|
||||||
*/
|
*/
|
||||||
public ResourceHolderSynchronization(ResourceHolder resourceHolder, Object resourceKey) {
|
public ResourceHolderSynchronization(H resourceHolder, K resourceKey) {
|
||||||
this.resourceHolder = resourceHolder;
|
this.resourceHolder = resourceHolder;
|
||||||
this.resourceKey = resourceKey;
|
this.resourceKey = resourceKey;
|
||||||
}
|
}
|
||||||
|
|
@ -56,6 +57,10 @@ public class ResourceHolderSynchronization implements TransactionSynchronization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
flushResource(this.resourceHolder);
|
||||||
|
}
|
||||||
|
|
||||||
public void beforeCommit(boolean readOnly) {
|
public void beforeCommit(boolean readOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,13 +128,20 @@ public class ResourceHolderSynchronization implements TransactionSynchronization
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush callback for the given resource holder.
|
||||||
|
* @param resourceHolder the resource holder to flush
|
||||||
|
*/
|
||||||
|
protected void flushResource(H resourceHolder) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After-commit callback for the given resource holder.
|
* After-commit callback for the given resource holder.
|
||||||
* Only called when the resource hasn't been released yet
|
* Only called when the resource hasn't been released yet
|
||||||
* ({@link #shouldReleaseBeforeCompletion()}).
|
* ({@link #shouldReleaseBeforeCompletion()}).
|
||||||
* @param resourceHolder the resource holder to process
|
* @param resourceHolder the resource holder to process
|
||||||
*/
|
*/
|
||||||
protected void processResourceAfterCommit(ResourceHolder resourceHolder) {
|
protected void processResourceAfterCommit(H resourceHolder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -137,7 +149,7 @@ public class ResourceHolderSynchronization implements TransactionSynchronization
|
||||||
* @param resourceHolder the resource holder to process
|
* @param resourceHolder the resource holder to process
|
||||||
* @param resourceKey the key that the ResourceHolder was bound for
|
* @param resourceKey the key that the ResourceHolder was bound for
|
||||||
*/
|
*/
|
||||||
protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
|
protected void releaseResource(H resourceHolder, K resourceKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -147,7 +159,7 @@ public class ResourceHolderSynchronization implements TransactionSynchronization
|
||||||
* @param committed whether the transaction has committed (<code>true</code>)
|
* @param committed whether the transaction has committed (<code>true</code>)
|
||||||
* or rolled back (<code>false</code>)
|
* or rolled back (<code>false</code>)
|
||||||
*/
|
*/
|
||||||
protected void cleanupResource(ResourceHolder resourceHolder, Object resourceKey, boolean committed) {
|
protected void cleanupResource(H resourceHolder, K resourceKey, boolean committed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2006 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -41,7 +41,7 @@ public class SimpleTransactionStatus extends AbstractTransactionStatus {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of the {@link SimpleTransactionStatus} class,
|
* Create a new instance of the {@link SimpleTransactionStatus} class,
|
||||||
* indicating a new transaction.
|
* indicating a new transaction.
|
||||||
*/
|
*/
|
||||||
public SimpleTransactionStatus() {
|
public SimpleTransactionStatus() {
|
||||||
|
|
@ -49,7 +49,7 @@ public class SimpleTransactionStatus extends AbstractTransactionStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of the {@link SimpleTransactionStatus} class.
|
* Create a new instance of the {@link SimpleTransactionStatus} class.
|
||||||
* @param newTransaction whether to indicate a new transaction
|
* @param newTransaction whether to indicate a new transaction
|
||||||
*/
|
*/
|
||||||
public SimpleTransactionStatus(boolean newTransaction) {
|
public SimpleTransactionStatus(boolean newTransaction) {
|
||||||
|
|
@ -58,7 +58,7 @@ public class SimpleTransactionStatus extends AbstractTransactionStatus {
|
||||||
|
|
||||||
|
|
||||||
public boolean isNewTransaction() {
|
public boolean isNewTransaction() {
|
||||||
return newTransaction;
|
return this.newTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2005 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -39,4 +39,10 @@ public interface SmartTransactionObject {
|
||||||
*/
|
*/
|
||||||
boolean isRollbackOnly();
|
boolean isRollbackOnly();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush the underlying sessions to the datastore, if applicable:
|
||||||
|
* for example, all affected Hibernate/JPA sessions.
|
||||||
|
*/
|
||||||
|
void flush();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2005 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -27,7 +27,7 @@ import org.springframework.transaction.TransactionStatus;
|
||||||
* @since 28.03.2003
|
* @since 28.03.2003
|
||||||
* @see TransactionTemplate
|
* @see TransactionTemplate
|
||||||
*/
|
*/
|
||||||
public abstract class TransactionCallbackWithoutResult implements TransactionCallback {
|
public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {
|
||||||
|
|
||||||
public final Object doInTransaction(TransactionStatus status) {
|
public final Object doInTransaction(TransactionStatus status) {
|
||||||
doInTransactionWithoutResult(status);
|
doInTransactionWithoutResult(status);
|
||||||
|
|
@ -35,10 +35,10 @@ public abstract class TransactionCallbackWithoutResult implements TransactionCal
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets called by TransactionTemplate.execute within a transactional context.
|
* Gets called by <code>TransactionTemplate.execute</code> within a transactional
|
||||||
* Does not need to care about transactions itself, although it can retrieve
|
* context. Does not need to care about transactions itself, although it can retrieve
|
||||||
* and influence the status of the current transaction via the given status
|
* and influence the status of the current transaction via the given status object,
|
||||||
* object, e.g. setting rollback-only.
|
* e.g. setting rollback-only.
|
||||||
*
|
*
|
||||||
* <p>A RuntimeException thrown by the callback is treated as application
|
* <p>A RuntimeException thrown by the callback is treated as application
|
||||||
* exception that enforces a rollback. An exception gets propagated to the
|
* exception that enforces a rollback. An exception gets propagated to the
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -60,6 +60,13 @@ public interface TransactionSynchronization {
|
||||||
*/
|
*/
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush the underlying session to the datastore, if applicable:
|
||||||
|
* for example, a Hibernate/JPA session.
|
||||||
|
* @see org.springframework.transaction.TransactionStatus#flush()
|
||||||
|
*/
|
||||||
|
void flush();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked before transaction commit (before "beforeCompletion").
|
* Invoked before transaction commit (before "beforeCompletion").
|
||||||
* Can e.g. flush transactional O/R Mapping sessions to the database.
|
* Can e.g. flush transactional O/R Mapping sessions to the database.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2006 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -42,6 +42,9 @@ public abstract class TransactionSynchronizationAdapter implements TransactionSy
|
||||||
public void resume() {
|
public void resume() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
}
|
||||||
|
|
||||||
public void beforeCommit(boolean readOnly) {
|
public void beforeCommit(boolean readOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -59,6 +59,17 @@ public abstract class TransactionSynchronizationUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger <code>flush</code> callbacks on all currently registered synchronizations.
|
||||||
|
* @throws RuntimeException if thrown by a <code>flush</code> callback
|
||||||
|
* @see TransactionSynchronization#flush()
|
||||||
|
*/
|
||||||
|
public static void triggerFlush() {
|
||||||
|
for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) {
|
||||||
|
synchronization.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger <code>beforeCommit</code> callbacks on all currently registered synchronizations.
|
* Trigger <code>beforeCommit</code> callbacks on all currently registered synchronizations.
|
||||||
* @param readOnly whether the transaction is defined as read-only transaction
|
* @param readOnly whether the transaction is defined as read-only transaction
|
||||||
|
|
@ -121,7 +132,7 @@ public abstract class TransactionSynchronizationUtils {
|
||||||
* @see TransactionSynchronization#STATUS_UNKNOWN
|
* @see TransactionSynchronization#STATUS_UNKNOWN
|
||||||
*/
|
*/
|
||||||
public static void triggerAfterCompletion(int completionStatus) {
|
public static void triggerAfterCompletion(int completionStatus) {
|
||||||
List synchronizations = TransactionSynchronizationManager.getSynchronizations();
|
List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
|
||||||
invokeAfterCompletion(synchronizations, completionStatus);
|
invokeAfterCompletion(synchronizations, completionStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue