DATAREDIS-988 - Consider transaction participation when releasing connections.

We now consider RedisTemplate's enableTransactionSupport configuration when releasing connections. Previously, we released bound connections when being in a read-only transaction regardless the configuration in RedisTemplate. This broke session callbacks that expected to remain on the same connection all but the first command were executed on a different connection.

Releasing a connection now no longer unbinds a connection if transaction support is disabled.

Original Pull Request: #453
This commit is contained in:
Mark Paluch
2019-06-03 11:05:05 +02:00
committed by Christoph Strobl
parent da1de92645
commit ae2042b1eb
3 changed files with 98 additions and 6 deletions

View File

@@ -28,14 +28,20 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.instrument.classloading.ShadowingClassLoader;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Unit tests for {@link RedisTemplate}.
*
* @author Christoph Strobl
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class RedisTemplateUnitTests {
@@ -47,6 +53,8 @@ public class RedisTemplateUnitTests {
@Before
public void setUp() {
TransactionSynchronizationManager.clear();
template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactoryMock);
when(connectionFactoryMock.getConnection()).thenReturn(redisConnectionMock);
@@ -96,6 +104,60 @@ public class RedisTemplateUnitTests {
verify(redisConnectionMock, never()).close();
}
@Test // DATAREDIS-988
public void executeSessionShouldReuseConnection() {
template.execute(new SessionCallback<Object>() {
@Nullable
@Override
public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
template.multi();
template.multi();
return null;
}
});
verify(connectionFactoryMock).getConnection();
verify(redisConnectionMock).close();
}
@Test // DATAREDIS-988
public void executeSessionInTransactionShouldReuseConnection() {
TransactionSynchronizationManager.setCurrentTransactionReadOnly(true);
template.execute(new SessionCallback<Object>() {
@Override
public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
template.multi();
template.multi();
return null;
}
});
verify(connectionFactoryMock).getConnection();
verify(redisConnectionMock).close();
}
@Test // DATAREDIS-988
public void transactionAwareTemplateShouldReleaseConnection() {
template.setEnableTransactionSupport(true);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(true);
template.execute(new SessionCallback<Object>() {
@Override
public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
template.multi();
template.multi();
return null;
}
});
verify(connectionFactoryMock, times(2)).getConnection();
verify(redisConnectionMock, times(2)).close();
}
static class SomeArbitrarySerializableObject implements Serializable {
private static final long serialVersionUID = -5973659324040506423L;
}