initialize transaction synchronization before doBegin call in order to avoid OutOfMemory failures after resource binding

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1986 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
Juergen Hoeller 2009-09-24 14:02:40 +00:00
parent 504db8f514
commit 614f52073c
2 changed files with 71 additions and 29 deletions

View File

@ -361,23 +361,31 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
DefaultTransactionStatus status = null;
try {
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
return status;
}
catch (RuntimeException ex) {
if (status != null && status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
if (status != null && status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
resume(null, suspendedResources);
throw err;
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
@ -414,20 +422,28 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
DefaultTransactionStatus status = null;
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
return status;
}
catch (RuntimeException beginEx) {
if (status != null && status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
catch (Error beginErr) {
if (status != null && status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
resumeAfterBeginException(transaction, suspendedResources, beginErr);
throw beginErr;
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
@ -452,9 +468,25 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
doBegin(transaction, definition);
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
try {
doBegin(transaction, definition);
}
catch (RuntimeException beginEx) {
if (status != null && status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
throw beginEx;
}
catch (Error beginErr) {
if (status != null && status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
throw beginErr;
}
return status;
}
}
@ -495,18 +527,27 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
boolean actualNewSynchronization = newSynchronization &&
!TransactionSynchronizationManager.isSynchronizationActive();
if (actualNewSynchronization) {
TransactionSynchronizationManager.setActualTransactionActive(transaction != null);
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
(definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) ?
definition.getIsolationLevel() : null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
TransactionSynchronizationManager.initSynchronization();
try {
if (actualNewSynchronization) {
TransactionSynchronizationManager.setActualTransactionActive(transaction != null);
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
(definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) ?
definition.getIsolationLevel() : null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
TransactionSynchronizationManager.initSynchronization();
}
return new DefaultTransactionStatus(
transaction, newTransaction, actualNewSynchronization,
definition.isReadOnly(), debug, suspendedResources);
}
catch (Error err) {
// Can only really be an OutOfMemoryError...
if (actualNewSynchronization) {
TransactionSynchronizationManager.clear();
}
throw err;
}
return new DefaultTransactionStatus(
transaction, newTransaction, actualNewSynchronization,
definition.isReadOnly(), debug, suspendedResources);
}
/**
@ -984,7 +1025,7 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
}
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction");
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
@ -1076,7 +1117,7 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
* @throws TransactionException in case of creation or system errors
*/
protected abstract void doBegin(Object transaction, TransactionDefinition definition)
throws TransactionException;
throws TransactionException;
/**
* Suspend the resources of the current transaction.

View File

@ -31,10 +31,10 @@ import org.springframework.transaction.SavepointManager;
* <p>Supports delegating savepoint-related methods to a transaction object
* that implements the {@link SavepointManager} interface.
*
* <p><b>NOTE:</b> This is <i>not</i> intended to be used for other
* PlatformTransactionManager implementations, in particular not for
* mock transaction managers. Use {@link SimpleTransactionStatus} or
* a mock for the plain TransactionStatus interface instead.
* <p><b>NOTE:</b> This is <i>not</i> intended for use with other PlatformTransactionManager
* implementations, in particular not for mock transaction managers in testing environments.
* Use the alternative {@link SimpleTransactionStatus} class or a mock for the plain
* {@link org.springframework.transaction.TransactionStatus} interface instead.
*
* @author Juergen Hoeller
* @since 19.01.2004
@ -77,7 +77,7 @@ public class DefaultTransactionStatus extends AbstractTransactionStatus {
* for this transaction, if any
*/
public DefaultTransactionStatus(
Object transaction, boolean newTransaction, boolean newSynchronization,
Object transaction, boolean newTransaction, boolean newSynchronization,
boolean readOnly, boolean debug, Object suspendedResources) {
this.transaction = transaction;
@ -88,6 +88,7 @@ public class DefaultTransactionStatus extends AbstractTransactionStatus {
this.suspendedResources = suspendedResources;
}
/**
* Return the underlying transaction object.
*/