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:
Juergen Hoeller
2009-02-19 00:24:05 +00:00
parent dd7d299aa4
commit 4cc42bf16f
34 changed files with 415 additions and 134 deletions

View File

@@ -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");
* 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.springframework.jca.cci.CannotGetCciConnectionException;
import org.springframework.transaction.support.ResourceHolder;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
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
* (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) {
super(connectionHolder, connectionFactory);
}
@Override
protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
releaseConnection(((ConnectionHolder) resourceHolder).getConnection(), (ConnectionFactory) resourceKey);
protected void releaseResource(ConnectionHolder resourceHolder, ConnectionFactory resourceKey) {
releaseConnection(resourceHolder.getConnection(), resourceKey);
}
}

View File

@@ -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");
* you may not use this file except in compliance with the License.
@@ -75,6 +75,12 @@ public interface TransactionStatus extends SavepointManager {
*/
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,
* whether it has already been committed or rolled back.

View File

@@ -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");
* 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.support.SmartTransactionObject;
import org.springframework.transaction.support.TransactionSynchronizationUtils;
/**
* 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();
}
}

View File

@@ -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");
* you may not use this file except in compliance with the License.
@@ -89,6 +89,12 @@ public abstract class AbstractTransactionStatus implements TransactionStatus {
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.
*/

View File

@@ -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");
* 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,
* 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
* by the transaction coordinator, for example in case of a timeout.
* @see SmartTransactionObject#isRollbackOnly
@@ -156,6 +156,16 @@ public class DefaultTransactionStatus extends AbstractTransactionStatus {
((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
* of the underlying transaction object, if any.

View File

@@ -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");
* you may not use this file except in compliance with the License.
@@ -23,11 +23,12 @@ package org.springframework.transaction.support;
* @author Juergen Hoeller
* @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;
@@ -38,7 +39,7 @@ public class ResourceHolderSynchronization implements TransactionSynchronization
* @param resourceKey the key to bind the ResourceHolder for
* @see TransactionSynchronizationManager#bindResource
*/
public ResourceHolderSynchronization(ResourceHolder resourceHolder, Object resourceKey) {
public ResourceHolderSynchronization(H resourceHolder, K resourceKey) {
this.resourceHolder = resourceHolder;
this.resourceKey = resourceKey;
}
@@ -56,6 +57,10 @@ public class ResourceHolderSynchronization implements TransactionSynchronization
}
}
public void flush() {
flushResource(this.resourceHolder);
}
public void beforeCommit(boolean readOnly) {
}
@@ -123,13 +128,20 @@ public class ResourceHolderSynchronization implements TransactionSynchronization
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.
* Only called when the resource hasn't been released yet
* ({@link #shouldReleaseBeforeCompletion()}).
* @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 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>)
* or rolled back (<code>false</code>)
*/
protected void cleanupResource(ResourceHolder resourceHolder, Object resourceKey, boolean committed) {
protected void cleanupResource(H resourceHolder, K resourceKey, boolean committed) {
}
}

View File

@@ -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");
* 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.
*/
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
*/
public SimpleTransactionStatus(boolean newTransaction) {
@@ -58,7 +58,7 @@ public class SimpleTransactionStatus extends AbstractTransactionStatus {
public boolean isNewTransaction() {
return newTransaction;
return this.newTransaction;
}
}

View File

@@ -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");
* you may not use this file except in compliance with the License.
@@ -39,4 +39,10 @@ public interface SmartTransactionObject {
*/
boolean isRollbackOnly();
/**
* Flush the underlying sessions to the datastore, if applicable:
* for example, all affected Hibernate/JPA sessions.
*/
void flush();
}

View File

@@ -1,12 +1,12 @@
/*
* 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");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -27,7 +27,7 @@ import org.springframework.transaction.TransactionStatus;
* @since 28.03.2003
* @see TransactionTemplate
*/
public abstract class TransactionCallbackWithoutResult implements TransactionCallback {
public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {
public final Object doInTransaction(TransactionStatus status) {
doInTransactionWithoutResult(status);
@@ -35,10 +35,10 @@ public abstract class TransactionCallbackWithoutResult implements TransactionCal
}
/**
* Gets called by TransactionTemplate.execute within a transactional 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
* object, e.g. setting rollback-only.
* Gets called by <code>TransactionTemplate.execute</code> within a transactional
* 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 object,
* e.g. setting rollback-only.
*
* <p>A RuntimeException thrown by the callback is treated as application
* exception that enforces a rollback. An exception gets propagated to the

View File

@@ -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");
* you may not use this file except in compliance with the License.
@@ -60,6 +60,13 @@ public interface TransactionSynchronization {
*/
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").
* Can e.g. flush transactional O/R Mapping sessions to the database.

View File

@@ -1,12 +1,12 @@
/*
* 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");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -42,6 +42,9 @@ public abstract class TransactionSynchronizationAdapter implements TransactionSy
public void resume() {
}
public void flush() {
}
public void beforeCommit(boolean readOnly) {
}

View File

@@ -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");
* 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.
* @param readOnly whether the transaction is defined as read-only transaction
@@ -121,7 +132,7 @@ public abstract class TransactionSynchronizationUtils {
* @see TransactionSynchronization#STATUS_UNKNOWN
*/
public static void triggerAfterCompletion(int completionStatus) {
List synchronizations = TransactionSynchronizationManager.getSynchronizations();
List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
invokeAfterCompletion(synchronizations, completionStatus);
}