DATAREDIS-548 - Release connection after command execution in read-only transactions.

We now unbind and release the connection from the transaction resources after a Redis command is invoked. Redis read operations return always null while using RedisTemplate in a transaction so Redis read transactions are not useful.

Previously, RedisConnection's were bound as transactional resource when used in the scope of a @Transactional(readOnly = true) method but not released on transaction completion. This was, because connections are not registered with a transaction synchronizer.

Original Pull Request: #214
This commit is contained in:
Mark Paluch
2016-08-24 10:14:21 +02:00
committed by Christoph Strobl
parent d6fee83042
commit 87f03bda95
3 changed files with 31 additions and 8 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2015 the original author or authors. * Copyright 2011-2016 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,6 +39,7 @@ import org.springframework.util.Assert;
* @author Costin Leau * @author Costin Leau
* @author Christoph Strobl * @author Christoph Strobl
* @author Thomas Darimont * @author Thomas Darimont
* @author Mark Paluch
*/ */
public abstract class RedisConnectionUtils { public abstract class RedisConnectionUtils {
@@ -199,8 +200,12 @@ public abstract class RedisConnectionUtils {
return; return;
} }
// Only release non-transactional/non-bound connections. // release transactional/read-only and non-transactional/non-bound connections.
if (!isConnectionTransactional(conn, factory)) { // transactional connections for read-only transactions get no synchronizer registered
if (isConnectionTransactional(conn, factory)
&& TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
unbindConnection(factory);
} else if (!isConnectionTransactional(conn, factory)) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Closing Redis Connection"); log.debug("Closing Redis Connection");
} }

View File

@@ -72,6 +72,7 @@ import org.springframework.util.CollectionUtils;
* @author Costin Leau * @author Costin Leau
* @author Christoph Strobl * @author Christoph Strobl
* @author Anqing Shao * @author Anqing Shao
* @author Mark Paluch
* @param <K> the Redis key type against which the template works (usually a String) * @param <K> the Redis key type against which the template works (usually a String)
* @param <V> the Redis value type against which the template works * @param <V> the Redis value type against which the template works
* @see StringRedisTemplate * @see StringRedisTemplate
@@ -199,10 +200,7 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
// TODO: any other connection processing? // TODO: any other connection processing?
return postProcessResult(result, connToUse, existingConnection); return postProcessResult(result, connToUse, existingConnection);
} finally { } finally {
RedisConnectionUtils.releaseConnection(conn, factory);
if (!enableTransactionSupport) {
RedisConnectionUtils.releaseConnection(conn, factory);
}
} }
} }

View File

@@ -40,6 +40,13 @@ import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/**
* Base class with integration tests for transactional use.
*
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
@RunWith(RelaxedJUnit4ClassRunner.class) @RunWith(RelaxedJUnit4ClassRunner.class)
@Transactional @Transactional
@TransactionConfiguration(transactionManager = "transactionManager") @TransactionConfiguration(transactionManager = "transactionManager")
@@ -131,6 +138,19 @@ public abstract class AbstractTransactionalTestBase {
} }
} }
/**
* @see DATAREDIS-548
*/
@Test
@Transactional(readOnly = true)
public void valueOperationShouldWorkWithReadOnlyTransactions() {
this.valuesShouldHaveBeenPersisted = false;
for (String key : KEYS) {
template.opsForValue().get(key);
}
}
/** /**
* @see DATAREDIS-73 * @see DATAREDIS-73
*/ */
@@ -148,7 +168,7 @@ public abstract class AbstractTransactionalTestBase {
*/ */
@Rollback(false) @Rollback(false)
@Test @Test
public void listOperationLPushShoudBeCommittedCorrectly() { public void listOperationLPushShouldBeCommittedCorrectly() {
this.valuesShouldHaveBeenPersisted = true; this.valuesShouldHaveBeenPersisted = true;
for (String key : KEYS) { for (String key : KEYS) {