From ef95fc2f7ef001f3f1a17aae3f83387a77db91a3 Mon Sep 17 00:00:00 2001 From: Stas Volsky Date: Thu, 22 Jan 2015 23:49:21 +0300 Subject: [PATCH] Synchronize clear on TransactionAwareCacheDecorator Previously, a cache decorated with TransactionAwareCacheDecorator would clear the cache immediately, even when a transaction is running. This commit updates the decorator to synchronize to the afterCommit phase for the clear operation as well. Issue: SPR-12653 --- .../TransactionAwareCacheDecorator.java | 23 +++++++++++----- .../TransactionAwareCacheDecoratorTests.java | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheDecorator.java b/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheDecorator.java index e239b96d1ee..4c5a7fdb174 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheDecorator.java +++ b/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheDecorator.java @@ -22,17 +22,18 @@ import org.springframework.transaction.support.TransactionSynchronizationManager import org.springframework.util.Assert; /** - * Cache decorator which synchronizes its {@link #put} and {@link #evict} operations with - * Spring-managed transactions (through Spring's {@link TransactionSynchronizationManager}, - * performing the actual cache put/evict operation only in the after-commit phase of a - * successful transaction. If no transaction is active, {@link #put} and {@link #evict} - * operations will be performed immediately, as usual. + * Cache decorator which synchronizes its {@link #put}, {@link #evict} and {@link #clear} + * operations with Spring-managed transactions (through Spring's {@link TransactionSynchronizationManager}, + * performing the actual cache put/evict/clear operation only in the after-commit phase of a + * successful transaction. If no transaction is active, {@link #put}, {@link #evict} and + * {@link #clear} operations will be performed immediately, as usual. * *

Use of more aggressive operations such as {@link #putIfAbsent} cannot be deferred * to the after-commit phase of a running transaction. Use these with care. * * @author Juergen Hoeller * @author Stephane Nicoll + * @author Stas Volsky * @since 3.2 * @see TransactionAwareCacheManagerProxy */ @@ -108,7 +109,17 @@ public class TransactionAwareCacheDecorator implements Cache { @Override public void clear() { - this.targetCache.clear(); + if (TransactionSynchronizationManager.isSynchronizationActive()) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { + @Override + public void afterCommit() { + targetCache.clear(); + } + }); + } + else { + this.targetCache.clear(); + } } } diff --git a/spring-context-support/src/test/java/org/springframework/cache/transaction/TransactionAwareCacheDecoratorTests.java b/spring-context-support/src/test/java/org/springframework/cache/transaction/TransactionAwareCacheDecoratorTests.java index 7b657240bd6..151615db55a 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/transaction/TransactionAwareCacheDecoratorTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/transaction/TransactionAwareCacheDecoratorTests.java @@ -128,4 +128,31 @@ public class TransactionAwareCacheDecoratorTests { assertNull(target.get(key)); } + @Test + public void clearNonTransactional() { + Cache target = new ConcurrentMapCache("testCache"); + Cache cache = new TransactionAwareCacheDecorator(target); + Object key = new Object(); + cache.put(key, "123"); + + cache.clear(); + assertNull(target.get(key)); + } + + @Test + public void clearTransactional() { + Cache target = new ConcurrentMapCache("testCache"); + Cache cache = new TransactionAwareCacheDecorator(target); + Object key = new Object(); + cache.put(key, "123"); + + + TransactionStatus status = txManager.getTransaction(new DefaultTransactionAttribute( + TransactionDefinition.PROPAGATION_REQUIRED)); + cache.clear(); + assertEquals("123", target.get(key, String.class)); + txManager.commit(status); + + assertNull(target.get(key)); + } }