diff --git a/src/main/asciidoc/reference/redis.adoc b/src/main/asciidoc/reference/redis.adoc index de39bc0e05..0cd68328bf 100644 --- a/src/main/asciidoc/reference/redis.adoc +++ b/src/main/asciidoc/reference/redis.adoc @@ -80,9 +80,15 @@ NOTE: For the corner cases where the native library API is required, `RedisConne Active `RedisConnection` objects are created through `RedisConnectionFactory`. In addition, the factory acts as `PersistenceExceptionTranslator` objects, meaning that, once declared, they let you do transparent exception translation. For example, you can do exception translation through the use of the `@Repository` annotation and AOP. For more information, see the dedicated {spring-framework-reference}/data-access.html#orm-exception-translation[section] in the Spring Framework documentation. -WARNING: `RedisConnection` classes, such as `JedisConnection` and `LettuceConnection`, are **not** Thread-safe. While the underlying native connection, such as Lettuce's `StatefulRedisConnection`, may be Thread-safe, Spring Data Redis's `LettuceConnection` class itself is not Thread-safe. Therefore, you should **not** share instances of a `RedisConnection` across multiple Threads. This is especially true for transactional, or blocking Redis operations and commands, such as `BLPOP`. In transactional and pipelining operations, for instance, `RedisConnection` holds onto unguarded mutable state to complete the operation correctly, thereby making it unsafe to use with multiple Threads. This is by design. - -TIP: If you need to share (stateful) Redis resources, like connections, across multiple Threads, for performance reasons or otherwise, then you should acquire the native connection and use the Redis client library (driver) API directly. Alternatively, you can use the `RedisTemplate`, which acquires and manages connections for operations (and Redis commands) in a Thread-safe manner. See <> on `RedisTemplate` for more details. +NOTE: `RedisConnection` classes are **not** Thread-safe. +While the underlying native connection, such as Lettuce's `StatefulRedisConnection`, may be Thread-safe, Spring Data Redis's `LettuceConnection` class itself is not. +Therefore, you should **not** share instances of a `RedisConnection` across multiple Threads. +This is especially true for transactional, or blocking Redis operations and commands, such as `BLPOP`. +In transactional and pipelining operations, for instance, `RedisConnection` holds onto unguarded mutable state to complete the operation correctly, thereby making it unsafe to use with multiple Threads. +This is by design. + +TIP: If you need to share (stateful) Redis resources, like connections, across multiple Threads, for performance reasons or otherwise, then you should acquire the native connection and use the Redis client library (driver) API directly. +Alternatively, you can use the `RedisTemplate`, which acquires and manages connections for operations (and Redis commands) in a Thread-safe manner. See <> on `RedisTemplate` for more details. NOTE: Depending on the underlying configuration, the factory can return a new connection or an existing connection (when a pool or shared native connection is used). diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java index cb079af4b3..2ffd7dc2b2 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java @@ -28,6 +28,9 @@ * {@link RedisClusterNode} can be obtained from {@link #clusterGetNodes()} or it can be constructed using either * {@link RedisClusterNode#getHost() host} and {@link RedisClusterNode#getPort()} or the {@link RedisClusterNode#getId() * node Id}. + *

+ * {@link RedisClusterConnection Redis connections}, unlike perhaps their underlying native connection are not + * Thread-safe and should not be shared across multiple threads. * * @author Christoph Strobl * @author Mark Paluch diff --git a/src/main/java/org/springframework/data/redis/connection/RedisConnection.java b/src/main/java/org/springframework/data/redis/connection/RedisConnection.java index c85b627b47..ded8e92880 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisConnection.java @@ -20,13 +20,13 @@ import org.springframework.dao.DataAccessException; /** - * A connection to a Redis server. Acts as an common abstraction across various Redis client libraries (or drivers). + * A connection to a Redis server. Acts as an common abstraction across various Redis client libraries (or + * drivers). * Additionally performs exception translation between the underlying Redis client library and Spring DAO exceptions. * The methods follow as much as possible the Redis names and conventions. *

- * Spring Data Redis {@link RedisConnection connections}, unlike perhaps their underlying native connection (for example: - * the Lettuce {@literal StatefulRedisConnection}) are not Thread-safe. Please refer to the corresponding the Javadoc - * for Redis client library (driver) specific connections provided by Spring Data Redis for more details. + * {@link RedisConnection Redis connections}, unlike perhaps their underlying native connection are not Thread-safe and + * should not be shared across multiple threads. * * @author Costin Leau * @author Christoph Strobl diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java index 0abb3e35d0..1752cb21ad 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java @@ -35,7 +35,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.PropertyAccessor; import org.springframework.dao.DataAccessException; @@ -61,6 +60,8 @@ * {@link RedisClusterConnection} implementation on top of {@link JedisCluster}.
* Uses the native {@link JedisCluster} api where possible and falls back to direct node communication using * {@link Jedis} where needed. + *

+ * This class is not Thread-safe and instances should not be shared across threads. * * @author Christoph Strobl * @author Mark Paluch diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index 850210cd7d..0c23bb1717 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -41,7 +41,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -60,10 +59,7 @@ /** * {@code RedisConnection} implementation on top of Jedis library. *

- * WARNING: The {@link JedisConnection} class is not Thread-safe. This class requires and uses a - * {@literal Jedis} instance from the Jedis client library (driver), which is very clearly - * documented - * as not Thread-safe. + * This class is not Thread-safe and instances should not be shared across threads. * * @author Costin Leau * @author Jennifer Hickey diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java index 9828cd219e..373a18d1d7 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java @@ -75,6 +75,11 @@ *

* This connection factory must be {@link #afterPropertiesSet() initialized} prior to {@link #getConnection obtaining * connections}. + *

+ * Note that {@link JedisConnection} and its {@link JedisClusterConnection clustered variant} are not Thread-safe and + * instances should not be shared across threads. Refer to the + * Jedis + * documentation for guidance on configuring Jedis in a multithreaded environment. * * @author Costin Leau * @author Thomas Darimont diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java index b923a26c6d..f3bd214bf2 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java @@ -32,7 +32,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.factory.DisposableBean; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -53,6 +52,13 @@ /** * {@code RedisClusterConnection} implementation on top of Lettuce * Redis client. + *

+ * While the underlying Lettuce {@literal RedisClient} and {@literal StatefulRedisConnection} instances used by + * {@link LettuceClusterConnection} are Thread-safe, this class itself is not Thread-safe. Therefore, instances of + * {@link LettuceClusterConnection} should not be shared across multiple Threads when executing Redis commands and other + * operations. If optimal performance is required by your application(s), then we recommend direct access to the + * low-level, API provided by the underlying Lettuce client library (driver), where such Thread-safety guarantees can be + * made. Simply call {@link #getNativeConnection()} and use the native resource as required. * * @author Christoph Strobl * @author Mark Paluch @@ -486,7 +492,6 @@ public void multi() { throw new InvalidDataAccessApiUsageException("MULTI is currently not supported in cluster mode"); } - public ClusterCommandExecutor getClusterCommandExecutor() { return clusterCommandExecutor; } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index f0ed270395..9d50e0f056 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -80,12 +80,12 @@ * {@code RedisConnection} implementation on top of Lettuce Redis * client. *

- * WARNING: While the underlying Lettuce {@literal RedisClient} and {@literal StatefulRedisConnection} instances used by - * {@link LettuceConnection} are Thread-safe, this class itself is not Thread-safe. Therefore, instances of {@link LettuceConnection} - * should not be shared across multiple Threads when executing Redis commands and other operations. If optimal performance - * is required by your application(s), then we recommend direct access to the low-level, API provided by the underlying - * Lettuce client library (driver), where such Thread-safety guarantees can be made. Simply call {@link #getNativeConnection()} - * and use the native resource as required. + * While the underlying Lettuce {@literal RedisClient} and {@literal StatefulRedisConnection} instances used by + * {@link LettuceConnection} are Thread-safe, this class itself is not Thread-safe. Therefore, instances of + * {@link LettuceConnection} should not be shared across multiple Threads when executing Redis commands and other + * operations. If optimal performance is required by your application(s), then we recommend direct access to the + * low-level, API provided by the underlying Lettuce client library (driver), where such Thread-safety guarantees can be + * made. Simply call {@link #getNativeConnection()} and use the native resource as required. * * @author Costin Leau * @author Jennifer Hickey diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index 37e8a0fb96..aebc3f51de 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -68,8 +68,10 @@ /** * Connection factory creating Lettuce-based connections. *

- * This factory creates a new {@link LettuceConnection} on each call to {@link #getConnection()}. Multiple - * {@link LettuceConnection}s share a single thread-safe native connection by default. + * This factory creates a new {@link LettuceConnection} on each call to {@link #getConnection()}. While multiple + * {@link LettuceConnection}s share a single thread-safe native connection by default, {@link LettuceConnection} and its + * {@link LettuceClusterConnection clustered variant} are not Thread-safe and instances should not be shared across + * threads. *

* The shared native connection is never closed by {@link LettuceConnection}, therefore it is not validated by default * on {@link #getConnection()}. Use {@link #setValidateConnection(boolean)} to change this behavior if necessary. If