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:
committed by
Christoph Strobl
parent
d6fee83042
commit
87f03bda95
@@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user