Spring Data Redis Version 1.7.1.RELEASE

Spring Boot 3.x连接Redis报错排查与解决方案 Redis作为高性能内存数据库,在Java生态中常通过Spring Data Redis集成。其核心原理基于内存键值存储,通过Lettuce或Jedis客户端实现连接。在Spring Boot 3.x版本升级过程中,开发者常遇到Redis连接失败问题,这通常涉及客户端兼容性、认证配置和连接池优化等技术要点。本文以Lettuce客户端为例,深入分析Unable to connect to Redis错误的排查路径,涵盖网络层检查、ACL认证配置、版本适配等关键环节,并提供生产级连接池配置和SSL/TLS设置的 阅读详情

© 2011-2016 The original authors. http://docs.spring.io/spring-data/redis/docs/1.7.1.RELEASE/reference/html/#tx

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
Table of Contents

Preface

The Spring Data Redis project applies core Spring concepts to the development of solutions using a key-value style data store. We provide a "template" as a high-level abstraction for sending and receiving messages. You will notice similarities to the JDBC support in the Spring Framework.

1. New Features

New and noteworthy in the latest releases.

1.1. New in Spring Data Redis 1.6

  • The Lettuce Redis driver switched from wg/lettuce to mp911de/lettuce.

  • Support for ZRANGEBYLEX.

  • Enhanced range operations for ZSET s including +inf / -inf.

  • Performance improvements in RedisCache now releasing connections earlier.

  • Generic Jackson2 RedisSerializer making use of Jackson’s polymorphic deserialization.

1.2. New in Spring Data Redis 1.5

  • Add support for Redis HyperLogLog commands PFADD, PFCOUNT and PFMERGE.

  • Configurable JavaType lookup for Jackson based RedisSerializers.

  • PropertySource based configuration for connecting to Redis Sentinel (see: Redis Sentinel Support).

Introduction

This document is the reference guide for Spring Data Redis (SDR) Support. It explains Key Value module concepts and semantics and the syntax for various stores namespaces.

For an introduction to key value stores or Spring, or Spring Data examples, please refer to Getting Started - this documentation refers only to Spring Data Redis Support and assumes the user is familiar with the key value storages and Spring concepts.

2. Why Spring Data Redis?

The Spring Framework is the leading full-stack Java/JEE application framework. It provides a lightweight container and a non-invasive programming model enabled by the use of dependency injection, AOP, and portable service abstractions.

NoSQL storages provide an alternative to classical RDBMS for horizontal scalability and speed. In terms of implementation, Key Value stores represent one of the largest (and oldest) members in the NoSQL space.

The Spring Data Redis (or SDR) framework makes it easy to write Spring applications that use the Redis key value store by eliminating the redundant tasks and boiler plate code required for interacting with the store through Spring’s excellent infrastructure support.

3. Requirements

Spring Data Redis 1.2.x binaries requires JDK level 6.0 and above, and Spring Framework 3.2.8 and above.

In terms of key value stores, Redis 2.6.x or higher is required. Spring Data Redis is currently tested against the latest 2.6 and 2.8 releases.

4. Getting Started

Learning a new framework is not always straight forward. In this section, we (the Spring Data team) tried to provide, what we think is, an easy to follow guide for starting with the Spring Data Redis module. Of course, feel free to create your own learning 'path' as you see fit and, if possible, please report back any improvements to the documentation that can help others.

4.1. First Steps

As explained in Why Spring Data Redis?, Spring Data Redis (SDR) provides integration between Spring framework and the Redis key value store. Thus, it is important to become acquainted with both of these frameworks (storages or environments depending on how you want to name them). Throughout the SDR documentation, each section provides links to resources relevant however, it is best to become familiar with these topics beforehand.

4.1.1. Knowing Spring

Spring Data uses heavily Spring framework’s core functionality, such as the IoC container, resource abstract or AOPinfrastructure. While it is not important to know the Spring APIs, understanding the concepts behind them is. At a minimum, the idea behind IoC should be familiar. That being said, the more knowledge one has about the Spring, the faster she will pick up Spring Data Redis. Besides the very comprehensive (and sometimes disarming) documentation that explains in detail the Spring Framework, there are a lot of articles, blog entries and books on the matter - take a look at the Spring Guides home page for more information. In general, this should be the starting point for developers wanting to try Spring DR.

4.1.2. Knowing NoSQL and Key Value stores

NoSQL stores have taken the storage world by storm. It is a vast domain with a plethora of solutions, terms and patterns (to make things worse even the term itself has multiple meanings). While some of the principles are common, it is crucial that the user is familiar to some degree with the stores supported by SDR. The best way to get acquainted with these solutions is to read their documentation and follow their examples - it usually doesn’t take more then 5-10 minutes to go through them and if you are coming from an RDMBS-only background many times these exercises can be an eye opener.

4.1.3. Trying Out The Samples

One can find various samples for key value stores in the dedicated example repo, at http://github.com/spring-projects/spring-data-keyvalue-examples. For Spring Data Redis, of interest is the retwisj sample, a Twitter-clone built on top of Redis which can be run locally or be deployed into the cloud. See its documentation, the following blog entry or thelive instance for more information.

4.2. Need Help?

If you encounter issues or you are just looking for advice, feel free to use one of the links below:

4.2.1. Community Support

The Spring Data tag on Stackoverflow is a message board for all Spring Data (not just Redis) users to share information and help each other. Note that registration is needed only for posting.

4.2.2. Professional Support

Professional, from-the-source support, with guaranteed response time, is available from Pivotal Software, Inc., the company behind Spring Data and Spring.

4.3. Following Development

For information on the Spring Data source code repository, nightly builds and snapshot artifacts please see the Spring Data home page.

You can help make Spring Data best serve the needs of the Spring community by interacting with developers on Stackoverflow at either spring-data or spring-data-redis.

If you encounter a bug or want to suggest an improvement, please create a ticket on the Spring Data issue tracker.

To stay up to date with the latest news and announcements in the Spring eco system, subscribe to the Spring CommunityPortal.

Lastly, you can follow the Spring blog or the project team (Thomas and Christoph) on Twitter.

Reference Documentation

Document structure

This part of the reference documentation explains the core functionality offered by Spring Data Redis.

Redis support introduces the Redis module feature set.

5. Redis support

One of the key value stores supported by Spring Data is Redis. To quote the project home page:

Redis is an advanced key-value store. It is similar to memcached but the dataset is not volatile, and values can be strings, exactly like in memcached, but also lists, sets, and ordered sets. All this data types can be manipulated with atomic operations to push/pop elements, add/remove elements, perform server side union, intersection, difference between sets, and so forth. Redis supports different kind of sorting abilities.

Spring Data Redis provides easy configuration and access to Redis from Spring applications. It offers both low-level and high-level abstractions for interacting with the store, freeing the user from infrastructural concerns.

5.1. Redis Requirements

Spring Redis requires Redis 2.6 or above and Java SE 6.0 or above . In terms of language bindings (or connectors), Spring Redis integrates with Jedis, JRedis (Deprecated since 1.7), SRP (Deprecated since 1.7) and Lettuce, four popular open source Java libraries for Redis. If you are aware of any other connector that we should be integrating with please send us feedback.

5.2. Redis Support High Level View

The Redis support provides several components (in order of dependencies):

For most tasks, the high-level abstractions and support services are the best choice. Note that at any point, one can move between layers - for example, it’s very easy to get a hold of the low level connection (or even the native library) to communicate directly with Redis.

5.3. Connecting to Redis

One of the first tasks when using Redis and Spring is to connect to the store through the IoC container. To do that, a Java connector (or binding) is required. No matter the library one chooses, there is only one set of Spring Data Redis API that one needs to use that behaves consistently across all connectors, namely theorg.springframework.data.redis.connection package and its RedisConnection and RedisConnectionFactoryinterfaces for working with and retrieving active connections to Redis.

5.3.1. RedisConnection and RedisConnectionFactory

RedisConnection provides the building block for Redis communication as it handles the communication with the Redis back-end. It also automatically translates the underlying connecting library exceptions to Spring’s consistent DAO exception hierarchy so one can switch the connectors without any code changes as the operation semantics remain the same.

For the corner cases where the native library API is required, RedisConnection provides a dedicated method getNativeConnection which returns the raw, underlying object used for communication.

Active RedisConnection s are created through RedisConnectionFactory. In addition, the factories act asPersistenceExceptionTranslator s, meaning once declared, they allow one to do transparent exception translation. For example, exception translation through the use of the @Repository annotation and AOP. For more information see the dedicated section in Spring Framework documentation.

Depending on the underlying configuration, the factory can return a new connection or an existing connection (in case a pool or shared native connection is used).

The easiest way to work with a RedisConnectionFactory is to configure the appropriate connector through the IoC container and inject it into the using class.

Unfortunately, currently, not all connectors support all Redis features. When invoking a method on the Connection API that is unsupported by the underlying library, an UnsupportedOperationException is thrown. This situation is likely to be fixed in the future, as the various connectors mature.
5.3.2. Configuring Jedis connector

Jedis is one of the connectors supported by the Spring Data Redis module through theorg.springframework.data.redis.connection.jedis package. In its simplest form, the Jedis configuration looks as follow:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <!-- Jedis ConnectionFactory -->
  <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"/>

</beans>

For production use however, one might want to tweak the settings such as the host or password:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="server" p:port="6379" />

</beans>
5.3.3. Configuring JRedis connector (Deprecated since 1.7)

JRedis is another popular, open-source connector supported by Spring Data Redis through theorg.springframework.data.redis.connection.jredis package.

A typical JRedis configuration can looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="jredisConnectionFactory" class="org.springframework.data.redis.connection.jredis.JredisConnectionFactory" p:host-name="server" p:port="6379"/>

</beans>

The configuration is quite similar to Jedis, with one notable exception. By default, the JedisConnectionFactory pools connections. In order to use a connection pool with JRedis, configure the JredisConnectionFactory with an instance ofJredisPool. For example:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="jredisConnectionFactory" class="org.springframework.data.redis.connection.jredis.JredisConnectionFactory">
    <constructor-arg>
      <bean class="org.springframework.data.redis.connection.jredis.DefaultJredisPool">
        <constructor-arg value="localhost" />
        <constructor-arg value="6379" />
      </bean>
    </constructor-arg>
  </bean>

</beans>
5.3.4. Configuring SRP connector (Deprecated since 1.7)

SRP (an acronym for Sam’s Redis Protocol) is the third open-source connector supported by Spring Data Redis through theorg.springframework.data.redis.connection.srp package.

By now, its configuration is probably easy to guess:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="srpConnectionFactory" class="org.springframework.data.redis.connection.srp.SrpConnectionFactory" p:host-name="server" p:port="6379"/>

</beans>

Needless to say, the configuration is quite similar to that of the other connectors.

5.3.5. Configuring Lettuce connector

Lettuce is the fourth open-source connector supported by Spring Data Redis through theorg.springframework.data.redis.connection.lettuce package.

Its configuration is probably easy to guess:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="lettuceConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory" p:host-name="server" p:port="6379"/>

</beans>

There are also a few Lettuce-specific connection parameters that can be tweaked. By default, all LettuceConnection s created by the LettuceConnectionFactory share the same thread-safe native connection for all non-blocking and non-transactional operations. Set shareNativeConnection to false to use a dedicated connection each time.LettuceConnectionFactory can also be configured with a LettucePool to use for pooling blocking and transactional connections, or all connections if shareNativeConnection is set to false.

5.4. Redis Sentinel Support

For dealing with high available Redis there is support for Redis Sentinel using RedisSentinelConfiguration.

Please note that currently only Jedis and lettuce Lettuce support Redis Sentinel.
/**
 * jedis
 */
@Bean
public RedisConnectionFactory jedisConnectionFactory() {
  RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster")
  .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380);
  return new JedisConnectionFactory(sentinelConfig);
}

/**
 * lettuce
 */
@Bean
public RedisConnectionFactory lettuceConnectionFactory() {
  RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration().master("mymaster")
  .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380);
  return new LettuceConnectionFactory(sentinelConfig);
}

RedisSentinelConfiguration can also be defined via PropertySource.

Configuration Properties
  • spring.redis.sentinel.master: name of the master node.

  • spring.redis.sentinel.nodes: Comma delimited list of host:port pairs.

Sometimes direct interaction with the one of the Sentinels is required. UsingRedisConnectionFactory.getSentinelConnection() or RedisConnection.getSentinelCommands() gives you access to the first active Sentinel configured.

5.5. Working with Objects through RedisTemplate

Most users are likely to use RedisTemplate and its coresponding package org.springframework.data.redis.core - the template is in fact the central class of the Redis module due to its rich feature set. The template offers a high-level abstraction for Redis interactions. While RedisConnection offers low level methods that accept and return binary values (byte arrays), the template takes care of serialization and connection management, freeing the user from dealing with such details.

Moreover, the template provides operations views (following the grouping from Redis command reference) that offer rich, generified interfaces for working against a certain type or certain key (through the KeyBound interfaces) as described below:

Table 1. Operational views
Interface Description

Key Type Operations

ValueOperations

Redis string (or value) operations

ListOperations

Redis list operations

SetOperations

Redis set operations

ZSetOperations

Redis zset (or sorted set) operations

HashOperations

Redis hash operations

HyperLogLogOperations

Redis HyperLogLog operations like (pfadd, pfcount,…​)

Key Bound Operations

BoundValueOperations

Redis string (or value) key bound operations

BoundListOperations

Redis list key bound operations

BoundSetOperations

Redis set key bound operations

BoundZSetOperations

Redis zset (or sorted set) key bound operations

BoundHashOperations

Redis hash key bound operations

Once configured, the template is thread-safe and can be reused across multiple instances.

Out of the box, RedisTemplate uses a Java-based serializer for most of its operations. This means that any object written or read by the template will be serialized/deserialized through Java. The serialization mechanism can be easily changed on the template, and the Redis module offers several implementations available in theorg.springframework.data.redis.serializer package - see Serializers for more information. You can also set any of the serializers to null and use RedisTemplate with raw byte arrays by setting the enableDefaultSerializer property to false. Note that the template requires all keys to be non-null - values can be null as long as the underlying serializer accepts them; read the javadoc of each serializer for more information.

For cases where a certain template view is needed, declare the view as a dependency and inject the template: the container will automatically perform the conversion eliminating the opsFor[X] calls:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>
  <!-- redis template definition -->
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnectionFactory"/>
  ...

</beans>
public class Example {

  // inject the actual template
  @Autowired
  private RedisTemplate<String, String> template;

  // inject the template as ListOperations
  @Resource(name="redisTemplate")
  private ListOperations<String, String> listOps;

  public void addLink(String userId, URL url) {
    listOps.leftPush(userId, url.toExternalForm());
  }
}

5.6. String-focused convenience classes

Since it’s quite common for the keys and values stored in Redis to be java.lang.String, the Redis modules provides two extensions to RedisConnection and RedisTemplate, respectively the StringRedisConnection (and itsDefaultStringRedisConnection implementation) and StringRedisTemplate as a convenient one-stop solution for intensive String operations. In addition to being bound to String keys, the template and the connection use theStringRedisSerializer underneath which means the stored keys and values are human readable (assuming the same encoding is used both in Redis and your code). For example:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>

  <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="jedisConnectionFactory"/>
  ...
</beans>
public class Example {

  @Autowired
  private StringRedisTemplate redisTemplate;

  public void addLink(String userId, URL url) {
    redisTemplate.opsForList().leftPush(userId, url.toExternalForm());
  }
}

As with the other Spring templates, RedisTemplate and StringRedisTemplate allow the developer to talk directly to Redis through the RedisCallback interface. This gives complete control to the developer as it talks directly to theRedisConnection. Note that the callback receives an instance of StringRedisConnection when aStringRedisTemplate is used.

public void useCallback() {

  redisTemplate.execute(new RedisCallback<Object>() {
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
      Long size = connection.dbSize();
      // Can cast to StringRedisConnection if using a StringRedisTemplate
      ((StringRedisConnection)connection).set("key", "value");
    }
   });
}

5.7. Serializers

From the framework perspective, the data stored in Redis is just bytes. While Redis itself supports various types, for the most part these refer to the way the data is stored rather than what it represents. It is up to the user to decide whether the information gets translated into Strings or any other objects. The conversion between the user (custom) types and raw data (and vice-versa) is handled in Spring Data Redis through the RedisSerializer interface (packageorg.springframework.data.redis.serializer) which as the name implies, takes care of the serialization process. Multiple implementations are available out of the box, two of which have been already mentioned before in this documentation: the StringRedisSerializer and the JdkSerializationRedisSerializer. However one can useOxmSerializer for Object/XML mapping through Spring 3 OXM support or either JacksonJsonRedisSerializer,Jackson2JsonRedisSerializer or `GenericJackson2JsonRedisSerializer for storing data in JSON format. Do note that the storage format is not limited only to values - it can be used for keys, values or hashes without any restrictions.

5.8. Redis Messaging/PubSub

Spring Data provides dedicated messaging integration for Redis, very similar in functionality and naming to the JMS integration in Spring Framework; in fact, users familiar with the JMS support in Spring should feel right at home.

Redis messaging can be roughly divided into two areas of functionality, namely the production or publication and consumption or subscription of messages, hence the shortcut pubsub (Publish/Subscribe). The RedisTemplate class is used for message production. For asynchronous reception similar to Java EE’s message-driven bean style, Spring Data provides a dedicated message listener container that is used to create Message-Driven POJOs (MDPs) and for synchronous reception, the RedisConnection contract.

The package org.springframework.data.redis.connection and org.springframework.data.redis.listenerprovide the core functionality for using Redis messaging.

5.8.1. Sending/Publishing messages

To publish a message, one can use, as with the other operations, either the low-level RedisConnection or the high-levelRedisTemplate. Both entities offer the publish method that accepts as an argument the message that needs to be sent as well as the destination channel. While RedisConnection requires raw-data (array of bytes), the RedisTemplate allow arbitrary objects to be passed in as messages:

// send message through connection RedisConnection con = ...
byte[] msg = ...
byte[] channel = ...
con.publish(msg, channel); // send message through RedisTemplate
RedisTemplate template = ...
template.convertAndSend("hello!", "world");
5.8.2. Receiving/Subscribing for messages

On the receiving side, one can subscribe to one or multiple channels either by naming them directly or by using pattern matching. The latter approach is quite useful as it not only allows multiple subscriptions to be created with one command but to also listen on channels not yet created at subscription time (as long as they match the pattern).

At the low-level, RedisConnection offers subscribe and pSubscribe methods that map the Redis commands for subscribing by channel respectively by pattern. Note that multiple channels or patterns can be used as arguments. To change the subscription of a connection or simply query whether it is listening or not, RedisConnection providesgetSubscription and isSubscribed method.

Subscription commands in Spring Data Redis are blocking. That is, calling subscribe on a connection will cause the current thread to block as it will start waiting for messages - the thread will be released only if the subscription is canceled, that is an additional thread invokes unsubscribe or pUnsubscribe on thesame connection. See message listener container below for a solution to this problem.

As mentioned above, once subscribed a connection starts waiting for messages. No other commands can be invoked on it except for adding new subscriptions or modifying/canceling the existing ones. That is, invoking anything other thensubscribe, pSubscribe, unsubscribe, or pUnsubscribe is illegal and will throw an exception.

In order to subscribe for messages, one needs to implement the MessageListener callback: each time a new message arrives, the callback gets invoked and the user code executed through onMessage method. The interface gives access not only to the actual message but to the channel it has been received through and the pattern (if any) used by the subscription to match the channel. This information allows the callee to differentiate between various messages not just by content but also through data.

Message Listener Containers

Due to its blocking nature, low-level subscription is not attractive as it requires connection and thread management for every single listener. To alleviate this problem, Spring Data offers RedisMessageListenerContainer which does all the heavy lifting on behalf of the user - users familiar with EJB and JMS should find the concepts familiar as it is designed as close as possible to the support in Spring Framework and its message-driven POJOs (MDPs)

RedisMessageListenerContainer acts as a message listener container; it is used to receive messages from a Redis channel and drive the MessageListener s that are injected into it. The listener container is responsible for all threading of message reception and dispatches into the listener for processing. A message listener container is the intermediary between an MDP and a messaging provider, and takes care of registering to receive messages, resource acquisition and release, exception conversion and the like. This allows you as an application developer to write the (possibly complex) business logic associated with receiving a message (and reacting to it), and delegates boilerplate Redis infrastructure concerns to the framework.

Furthermore, to minimize the application footprint, RedisMessageListenerContainer allows one connection and one thread to be shared by multiple listeners even though they do not share a subscription. Thus no matter how many listeners or channels an application tracks, the runtime cost will remain the same through out its lifetime. Moreover, the container allows runtime configuration changes so one can add or remove listeners while an application is running without the need for restart. Additionally, the container uses a lazy subscription approach, using a RedisConnectiononly when needed - if all the listeners are unsubscribed, cleanup is automatically performed and the used thread released.

To help with the asynch manner of messages, the container requires a java.util.concurrent.Executor ( or Spring’sTaskExecutor) for dispatching the messages. Depending on the load, the number of listeners or the runtime environment, one should change or tweak the executor to better serve her needs - in particular in managed environments (such as app servers), it is highly recommended to pick a a proper TaskExecutor to take advantage of its runtime.

The MessageListenerAdapter

The MessageListenerAdapter class is the final component in Spring’s asynchronous messaging support: in a nutshell, it allows you to expose almost any class as a MDP (there are of course some constraints).

Consider the following interface definition. Notice that although the interface doesn’t extend the MessageListenerinterface, it can still be used as a MDP via the use of the MessageListenerAdapter class. Notice also how the various message handling methods are strongly typed according to the contents of the various Message types that they can receive and handle. In addition, the channel or pattern to which a message is sent can be passed in to the method as the second argument of type String:

public interface MessageDelegate {
  void handleMessage(String message);
  void handleMessage(Map message); void handleMessage(byte[] message);
  void handleMessage(Serializable message);
  // pass the channel/pattern as well
  void handleMessage(Serializable message, String channel);
 }
public class DefaultMessageDelegate implements MessageDelegate {
  // implementation elided for clarity...
}

In particular, note how the above implementation of the MessageDelegate interface (the aboveDefaultMessageDelegate class) has no Redis dependencies at all. It truly is a POJO that we will make into an MDP via the following configuration.

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:redis="http://www.springframework.org/schema/redis"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis.xsd">

<!-- the default ConnectionFactory -->
<redis:listener-container>
  <!-- the method attribute can be skipped as the default method name is "handleMessage" -->
  <redis:listener ref="listener" method="handleMessage" topic="chatroom" />
</redis:listener-container>

<bean id="listener" class="redisexample.DefaultMessageDelegate"/>
 ...
<beans>
The listener topic can be either a channel (e.g. topic="chatroom") or a pattern (e.g. topic="*room")

The example above uses the Redis namespace to declare the message listener container and automatically register the POJOs as listeners. The full blown, beans definition is displayed below:

<bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
  <constructor-arg>
    <bean class="redisexample.DefaultMessageDelegate"/>
  </constructor-arg>
</bean>

<bean id="redisContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
  <property name="connectionFactory" ref="connectionFactory"/>
  <property name="messageListeners">
    <map>
      <entry key-ref="messageListener">
        <bean class="org.springframework.data.redis.listener.ChannelTopic">
          <constructor-arg value="chatroom">
        </bean>
      </entry>
    </map>
  </property>
</bean>

Each time a message is received, the adapter automatically performs translation (using the configuredRedisSerializer) between the low-level format and the required object type transparently. Any exception caused by the method invocation is caught and handled by the container (by default, being logged).

5.9. Redis Transactions

Redis provides support for transactions through the multi, exec, and discard commands. These operations are available on RedisTemplate, however RedisTemplate is not guaranteed to execute all operations in the transaction using the same connection.

Spring Data Redis provides the SessionCallback interface for use when multiple operations need to be performed with the same connection, as when using Redis transactions. For example:

//execute a transaction
List<Object> txResults = redisTemplate.execute(new SessionCallback<List<Object>>() {
  public List<Object> execute(RedisOperations operations) throws DataAccessException {
    operations.multi();
    operations.opsForSet().add("key", "value1");

    // This will contain the results of all ops in the transaction
    return operations.exec();
  }
});
System.out.println("Number of items added to set: " + txResults.get(0));

RedisTemplate will use its value, hash key, and hash value serializers to deserialize all results of exec before returning. There is an additional exec method that allows you to pass a custom serializer for transaction results.

An important change has been made to the exec methods of RedisConnection and RedisTemplate in version 1.1. Previously these methods returned the results of transactions directly from the connectors. This means that the data types often differed from those returned from the methods of RedisConnection. For example, zAdd returns a boolean indicating that the element has been added to the sorted set. Most connectors return this value as a long and Spring Data Redis performs the conversion. Another common difference is that most connectors return a status reply (usually the String "OK") for operations like set. These replies are typically discarded by Spring Data Redis. Prior to 1.1, these conversions were not performed on the results of exec. Also, results were not deserialized in RedisTemplate, so they often included raw byte arrays. If this change breaks your application, you can setconvertPipelineAndTxResults to false on your RedisConnectionFactory to disable this behavior.
5.9.1. @Transactional Support

Transaction Support is disabled by default and has to be explicitly enabled for each RedisTemplate in use by settingsetEnableTransactionSupport(true). This will force binding the RedisConnection in use to the current Threadtriggering MULTI. If the transaction finishes without errors, EXEC is called, otherwise DISCARD. Once in MULTI,RedisConnection would queue write operations, all readonly operations, such as KEYS are piped to a fresh (non thread bound) RedisConnection.

/** Sample Configuration **/
@Configuration
public class RedisTxContextConfiguration {
  @Bean
  public StringRedisTemplate redisTemplate() {
    StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory());
    // explicitly enable transaction support
    template.setEnableTransactionSupport(true);
    return template;
  }

  @Bean
  public PlatformTransactionManager transactionManager() throws SQLException {
    return new DataSourceTransactionManager(dataSource());
  }

  @Bean
  public RedisConnectionFactory redisConnectionFactory( // jedis, lettuce, srp,... );

  @Bean
  public DataSource dataSource() throws SQLException { // ... }
}
/** Usage Constrainsts **/

// executed on thread bound connection
template.opsForValue().set("foo", "bar");

// read operation executed on a free (not tx-aware)
connection template.keys("*");

// returns null as values set within transaction are not visible
template.opsForValue().get("foo");

5.10. Pipelining

Redis provides support for pipelining, which involves sending multiple commands to the server without waiting for the replies and then reading the replies in a single step. Pipelining can improve performance when you need to send several commands in a row, such as adding many elements to the same List.

Spring Data Redis provides several RedisTemplate methods for executing commands in a pipeline. If you don’t care about the results of the pipelined operations, you can use the standard execute method, passing true for the pipelineargument. The executePipelined methods will execute the provided RedisCallback or SessionCallback in a pipeline and return the results. For example:

//pop a specified number of items from a queue
List<Object> results = stringRedisTemplate.executePipelined(
  new RedisCallback<Object>() {
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
      StringRedisConnection stringRedisConn = (StringRedisConnection)connection;
      for(int i=0; i< batchSize; i++) {
        stringRedisConn.rPop("myqueue");
      }
    return null;
  }
});

The example above executes a bulk right pop of items from a queue in a pipeline. The results List contains all of the popped items. RedisTemplate uses its value, hash key, and hash value serializers to deserialize all results before returning, so the returned items in the above example will be Strings. There are additional executePipelined methods that allow you to pass a custom serializer for pipelined results.

Note that the value returned from the RedisCallback is required to be null, as this value is discarded in favor of returning the results of the pipelined commands.

An important change has been made to the closePipeline method of RedisConnection in version 1.1. Previously this method returned the results of pipelined operations directly from the connectors. This means that the data types often differed from those returned by the methods of RedisConnection. For example, zAdd returns a boolean indicating that the element has been added to the sorted set. Most connectors return this value as a long and Spring Data Redis performs the conversion. Another common difference is that most connectors return a status reply (usually the String "OK") for operations like set. These replies are typically discarded by Spring Data Redis. Prior to 1.1, these conversions were not performed on the results of closePipeline. If this change breaks your application, you can setconvertPipelineAndTxResults to false on your RedisConnectionFactory to disable this behavior.

5.11. Redis Scripting

Redis versions 2.6 and higher provide support for execution of Lua scripts through the eval and evalsha commands. Spring Data Redis provides a high-level abstraction for script execution that handles serialization and automatically makes use of the Redis script cache.

Scripts can be run through the execute methods of RedisTemplate. RedisTemplate uses a configurableScriptExecutor to execute the provided script. By default, the ScriptExecutor takes care of serializing the provided keys and arguments and deserializing the script result. This is done with the RedisTemplate key and value serializers. There is an additional execute method that allows you to pass custom serializers for the script arguments and result.

The default ScriptExecutor optimizes performance by retrieving the SHA1 of the script and attempting first to runevalsha, falling back to eval if the script is not yet present in the Redis script cache.

Here’s an example that executes a common "check-and-set" scenario using a Lua script. This is an ideal use case for a Redis script, as it requires that we execute a set of commands atomically and the behavior of one command is influenced by the result of another.

@Bean
public RedisScript<Boolean> script() {
  DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<Boolean>();
  redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("META-INF/scripts/checkandset.lua")));
  redisScript.setResultType(Boolean.class);
}
public class Example {
  @Autowired
  RedisScript<Boolean> script;
  public boolean checkAndSet(String expectedValue, String newValue) {
    return redisTemplate.execute(script, Collections.singletonList("key"), expectedValue, newValue);
  }
}
 -- checkandset.lua local
 current = redis.call('GET', KEYS[1])
 if current == ARGV[1]
   then redis.call('SET', KEYS[1], ARGV[2])
   return true
 end
 return false

The XML above configures a DefaultRedisScript pointing to a file called checkandset.lua, which is expected to return a boolean value. The script resultType should be one of Long, Boolean, List, or deserialized value type. It can also be null if the script returns a throw-away status (i.e "OK"). It is ideal to configure a single instance ofDefaultRedisScript in your application context to avoid re-calculation of the script’s SHA1 on every script execution.

The checkAndSet method above then executes th Scripts can be executed within a SessionCallback as part of a transaction or pipeline. See Redis Transactions and Pipelining for more information.

The scripting support provided by Spring Data Redis also allows you to schedule Redis scripts for periodic execution using the Spring Task and Scheduler abstractions. See the Spring Framework documentation for more details.

5.12. Support Classes

Package org.springframework.data.redis.support offers various reusable components that rely on Redis as a backing store. Currently the package contains various JDK-based interface implementations on top of Redis such as atomiccounters and JDK Collections.

The atomic counters make it easy to wrap Redis key incrementation while the collections allow easy management of Redis keys with minimal storage exposure or API leakage: in particular the RedisSet and RedisZSet interfaces offer easy access to the set operations supported by Redis such as intersection and union while RedisList implements theList, Queue and Deque contracts (and their equivalent blocking siblings) on top of Redis, exposing the storage as a FIFO (First-In-First-Out), LIFO (Last-In-First-Out) or capped collection with minimal configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="queue" class="org.springframework.data.redis.support.collections.DefaultRedisList">
    <constructor-arg ref="redisTemplate"/>
    <constructor-arg value="queue-key"/>
  </bean>

</beans>
public class AnotherExample {

  // injected
  private Deque<String> queue;

  public void addTag(String tag) {
    queue.push(tag);
  }
}

As shown in the example above, the consuming code is decoupled from the actual storage implementation - in fact there is no indication that Redis is used underneath. This makes moving from development to production environments transparent and highly increases testability (the Redis implementation can just as well be replaced with an in-memory one).

5.12.1. Support for Spring Cache Abstraction

Spring Redis provides an implementation for Spring cache abstraction through theorg.springframework.data.redis.cache package. To use Redis as a backing implementation, simply addRedisCacheManager to your configuration:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:cache="http://www.springframework.org/schema/cache"
  xmlns:c="http://www.springframework.org/schema/c"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

  <!-- turn on declarative caching -->
  <cache:annotation-driven />

  <!-- declare Redis Cache Manager -->
  <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager" c:template-ref="redisTemplate"/>
</beans>
By default RedisCacheManager will lazily initialize RedisCache whenever a Cache is requested. This can be changed by predefining a Set of cache names.
By default RedisCacheManager will not participate in any ongoing transaction. UsesetTransactionAware to enable transaction support.
By default RedisCacheManager does not prefix keys for cache regions, which can lead to an unexpected growth of a ZSET used to maintain known keys. It’s highly recommended to enable the usage of prefixes in order to avoid this unexpected growth and potential key clashes using more than one cache region.

6. Redis Cluster

Working with Redis Cluster requires a Redis Server version 3.0+ and provides a very own set of features and capabilities. Please refer to the Cluster Tutorial for more information.

Redis Cluster is only supported by jedis and lettuce.

6.1. Enabling Redis Cluster

Cluster support is based on the very same building blocks as non clustered communication. RedisClusterConnectionan extension to RedisConnection handles the communication with the Redis Cluster and translates errors into the Spring DAO exception hierarchy. RedisClusterConnection 's are created via the RedisConnectionFactory which has to be set up with the according RedisClusterConfiguration.

Example 1. Sample RedisConnectionFactory Configuration for Redis Cluster
@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class ClusterConfigurationProperties {

    /*
     * spring.redis.cluster.nodes[0] = 127.0.0.1:7379
     * spring.redis.cluster.nodes[1] = 127.0.0.1:7380
     * ...
     */
    List<String> nodes;

    /**
     * Get initial collection of known cluster nodes in format {@code host:port}.
     *
     * @return
     */
    public List<String> getNodes() {
        return nodes;
    }

    public void setNodes(List<String> nodes) {
        this.nodes = nodes;
    }
}

@Configuration
public class AppConfig {

    /**
     * Type safe representation of application.properties
     */
    @Autowired ClusterConfigurationProperties clusterProperties;

    public @Bean RedisConnectionFactory connectionFactory() {

        return new JedisConnectionFactory(
            new RedisClusterConfiguration(clusterProperties.getNodes()));
    }
}

RedisClusterConfiguration can also be defined via PropertySource.

Configuration Properties
  • spring.redis.cluster.nodes: Comma delimited list of host:port pairs.

  • spring.redis.cluster.max-redirects: Number of allowed cluster redirections.

The initial configuration points driver libraries to an initial set of cluster nodes. Changes resulting from live cluster reconfiguration will only be kept in the native driver and not be written back to the configuration.

6.2. Working With Redis Cluster Connection

As mentioned above Redis Cluster behaves different from single node Redis or even a Sentinel monitored master slave environment. This is reasoned by the automatic sharding that maps a key to one of 16384 slots which are distributed across the nodes. Therefore commands that involve more than one key must assert that all keys map to the exact same slot in order to avoid cross slot execution errors. Further on, hence a single cluster node, only serves a dedicated set of keys, commands issued against one particular server only return results for those keys served by the server. As a very simple example take the KEYS command. When issued to a server in cluster environment it only returns the keys served by the node the request is sent to and not necessarily all keys within the cluster. So to get all keys in cluster environment it is necessary to read the keys from at least all known master nodes.

While redirects for to a specific keys to the corresponding slot serving node are handled by the driver libraries, higher level functions like collecting information across nodes, or sending commands to all nodes in the cluster that are covered by RedisClusterConnection. Picking up the keys example from just before, this means, that the keys(pattern)method picks up every master node in cluster and simultaneously executes the KEYS command on every single one, while picking up the results and returning the cumulated set of keys. To just request the keys of a single nodeRedisClusterConnection provides overloads for those (like keys(node, pattern) ).

A RedisClusterNode can be obtained from RedisClusterConnection.clusterGetNodes or it can be constructed using either host and port or the node Id.

Example 2. Sample of Running Commands Across the Cluster
redis-cli@127.0.0.1:7379 > cluster nodes

6b38bb... 127.0.0.1:7379 master - 0 0 25 connected 0-5460                      
7bb78c... 127.0.0.1:7380 master - 0 1449730618304 2 connected 5461-10922       
164888... 127.0.0.1:7381 master - 0 1449730618304 3 connected 10923-16383      
b8b5ee... 127.0.0.1:7382 slave 6b38bb... 0 1449730618304 25 connected          
RedisClusterConnection connection = connectionFactory.getClusterConnnection();

connection.set("foo", value);                                                  
connection.set("bar", value);                                                  

connection.keys("*");                                                          

connection.keys(NODE_7379, "*");                                               
connection.keys(NODE_7380, "*");                                               
connection.keys(NODE_7381, "*");                                               
connection.keys(NODE_7382, "*");                                               
Master node serving slots 0 to 5460 replicated to slave at 7382
Master node serving slots 5461 to 10922
Master node serving slots 10923 to 16383
Slave node holding replicates of master at 7379
Request routed to node at 7381 serving slot 12182
Request routed to node at 7379 serving slot 5061
Request routed to nodes at 7379, 7380, 7381 → [foo, bar]
Request routed to node at 7379 → [bar]
Request routed to node at 7380 → []
Request routed to node at 7381 → [foo]
Request routed to node at 7382 → [bar]

Cross slot requests such as MGET are automatically served by the native driver library when all keys map to the same slot. However once this is not the case RedisClusterConnection executes multiple parallel GET commands against the slot serving nodes and again returns a cumulated result. Obviously this is less performing than the single slot execution and therefore should be used with care. In doubt please consider pinning keys to the same slot by providing a prefix in curly brackets like {my-prefix}.foo and {my-prefix}.bar which will both map to the same slot number.

Example 3. Sample of Cross Slot Request Handling
redis-cli@127.0.0.1:7379 > cluster nodes

6b38bb... 127.0.0.1:7379 master - 0 0 25 connected 0-5460                      
7bb...
RedisClusterConnection connection = connectionFactory.getClusterConnnection();

connection.set("foo", value);         // slot: 12182
connection.set("{foo}.bar", value);   // slot: 12182
connection.set("bar", value);         // slot:  5461

connection.mGet("foo", "{foo}.bar");                                           

connection.mGet("foo", "bar");                                                 
Same Configuration as in the sample before.
Keys map to same slot → 127.0.0.1:7381 MGET foo {foo}.bar
Keys map to different slots and get split up into single slot ones routed to the according nodes
→ 127.0.0.1:7379 GET bar
→ 127.0.0.1:7381 GET foo
The above provided simple examples to demonstrate the general strategy followed by Spring Data Redis. Be aware that some operations might require loading huge amounts of data into memory in order to compute the desired command. Additionally not all cross slot requests can safely be ported to multiple single slot requests and will error if misused (eg. PFCOUNT ).

6.3. Working With RedisTemplate and ClusterOperations

Please refer to the section Working with Objects through RedisTemplate to read about general purpose, configuration and usage of RedisTemplate.

Please be careful when setting up RedisTemplate#keySerializer using any of the JsonRedisSerializers as changing json structure has immediate influence on hash slot calculation.

RedisTemplate provides access to cluster specific operations via the ClusterOperations interface that can be obtained via RedisTemplate.opsForCluster(). This allows to execute commands explicitly on a single node within the cluster while retaining de-/serialization features configured for the template and provides administrative commands such asCLUSTER MEET or more high level operations for eg. resharding.

Example 4. Accessing RedisClusterConnection via RedisTemplate
ClusterOperations clusterOps = redisTemplate.opsForCluster();
clusterOps.shutdown(NODE_7379);                                              
Shut down node at 7379 and cross fingers there is a slave in place that can take over.

7. Redis Repositories

Working with Redis Repositories allows to seamlessly convert and store domain objects in Redis Hashes, apply custom mapping strategies and make use of secondary indexes.

Redis Repositories requires at least Redis Server version 2.8.0.

7.1. Usage

To access domain entities stored in a Redis you can leverage repository support that eases implementing those quite significantly.

Example 5. Sample Person Entity
@RedisHash("persons")
public class Person {

  @Id String id;
  String firstname;
  String lastname;
  Address address;
}

We have a pretty simple domain object here. Note that it has a property named id annotated withorg.springframework.data.annotation.Id and a @RedisHash annotation on its type. Those two are responsible for creating the actual key used to persist the hash.

Properties annotated with @Id as well as those named id are considered as the identifier properties. Those with the annotation are favored over others.

To now actually have a component responsible for storage and retrieval we need to define a repository interface.

Example 6. Basic Repository Interface To Persist Person Entities
public interface PersonRepository extends CrudRepository<Person, String> {

}

As our repository extends CrudRepository it provides basic CRUD and finder operations. The thing we need in between to glue things together is the according Spring configuration.

Example 7. JavaConfig for Redis Repositories
@Configuration
@EnableRedisRepositories
public class ApplicationConfig {

  @Bean
  public RedisConnectionFactory connectionFactory() {
    return new JedisConnectionFactory();
  }

  @Bean
  public RedisTemplate<?, ?> redisTemplate() {

    RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
    return template;
  }
}

Given the setup above we can go on and inject PersonRepository into our components.

Example 8. Access to Person Entities
@Autowired PersonRepository repo;

public void basicCrudOperations() {

  Person rand = new Person("rand", "al'thor");
  rand.setAddress(new Address("emond's field", "andor"));

  repo.save(rand);                                         

  repo.findOne(rand.getId());                              

  repo.count();                                            

  repo.delete(rand);                                       
}
Generates a new id if current value is null or reuses an already set id value and stores properties of type Personinside the Redis Hash with key with pattern keyspace:id in this case eg. persons:5d67b7e1-8640-4475-beeb-c666fab4c0e5.
Uses the provided id to retrieve the object stored at keyspace:id.
Counts the total number of entities available within the keyspace persons defined by @RedisHash on Person.
Removes the key for the given object from Redis.

7.2. Object to Hash Mapping

The Redis Repository support persists Objects in Hashes. This requires an Object to Hash conversion which is done by aRedisConverter. The default implementation uses Converter for mapping property values to and from Redis nativebyte[].

Given the Person type from the previous sections the default mapping looks like the following:

_class = org.example.Person                 
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand                            
lastname = al’thor
address.city = emond's field                
address.country = andor
The _class attribute is included on root level as well as on any nested interface or abstract types.
Simple property values are mapped by path.
Properties of complex types are mapped by their dot path.
Table 2. Default Mapping Rules
Type Sample Mapped Value

Simple Type
(eg. String)

String firstname = "rand";

firstname = "rand"

Complex Type
(eg. Address)

Address adress = new Address("emond’s field");

address.city = "emond’s field"

List
of Simple Type

List<String> nicknames = asList("dragon reborn", "lews therin");

nicknames.[0] = "dragon reborn",
nicknames.[1] = "lews therin"

Map
of Simple Type

Map<String, String> atts = asMap({"eye-color", "grey"}, {"…​

atts.[eye-color] = "grey",
atts.[hair-color] = "…​

List
of Complex Type

List<Address> addresses = asList(new Address("em…​

addresses.[0].city = "emond’s field",
addresses.[1].city = "…​

Map
of Complex Type

Map<String, Address> addresses = asMap({"home", new Address("em…​

addresses.[home].city = "emond’s field",
addresses.[work].city = "…​

Mapping behavior can be customized by registering the according Converter in CustomConversions. Those converters can take care of converting from/to a single byte[] as well as Map<String,byte[]> whereas the first one is suitable for eg. converting one complex type to eg. a binary JSON representation that still uses the default mappings hash structure. The second option offers full control over the resulting hash. Writing objects to a Redis hash will delete the content from the hash and re-create the whole hash, so not mapped data will be lost.

Example 9. Sample byte[] Converters
@WritingConverter
public class AddressToBytesConverter implements Converter<Address, byte[]> {

  private final Jackson2JsonRedisSerializer<Address> serializer;

  public AddressToBytesConverter() {

    serializer = new Jackson2JsonRedisSerializer<Address>(Address.class);
    serializer.setObjectMapper(new ObjectMapper());
  }

  @Override
  public byte[] convert(Address value) {
    return serializer.serialize(value);
  }
}

@ReadingConverter
public class BytesToAddressConverter implements Converter<byte[], Address> {

  private final Jackson2JsonRedisSerializer<Address> serializer;

  public BytesToAddressConverter() {

    serializer = new Jackson2JsonRedisSerializer<Address>(Address.class);
    serializer.setObjectMapper(new ObjectMapper());
  }

  @Override
  public Address convert(byte[] value) {
    return serializer.deserialize(value);
  }
}

Using the above byte[] Converter produces eg.

_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = al’thor
address = { city : "emond's field", country : "andor" }
Example 10. Sample Map<String,byte[]> Converters
@WritingConverter
public class AddressToMapConverter implements Converter<Address, Map<String,byte[]>> {

  @Override
  public Map<String,byte[]> convert(Address source) {
    return singletonMap("ciudad", source.getCity().getBytes());
  }
}

@ReadingConverter
public class MapToAddressConverter implements Converter<Address, Map<String, byte[]>> {

  @Override
  public Address convert(Map<String,byte[]> source) {
    return new Address(new String(source.get("ciudad")));
  }
}

Using the above Map Converter produces eg.

_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = al’thor
ciudad = "emond's field"
Custom conversions have no effect on index resolution. Secondary Indexes will still be created even for custom converted types.

7.3. Keyspaces

Keyspaces define prefixes used to create the actual key for the Redis Hash. By default the prefix is set togetClass().getName(). This default can be altered via @RedisHash on aggregate root level or by setting up a programmatic configuration. However, the annotated keyspace supersedes any other configuration.

Example 11. Keyspace Setup via @EnableRedisRepositories
@Configuration
@EnableRedisRepositories(keyspaceConfiguration = MyKeyspaceConfiguration.class)
public class ApplicationConfig {

  //... RedisConnectionFactory and RedisTemplate Bean definitions omitted

  public static class MyKeyspaceConfiguration extends KeyspaceConfiguration {

    @Override
    protected Iterable<KeyspaceSettings> initialConfiguration() {
      return Collections.singleton(new KeyspaceSettings(Person.class, "persons"));
    }
  }
}
Example 12. Programmatic Keyspace setup
@Configuration
@EnableRedisRepositories
public class ApplicationConfig {

  //... RedisConnectionFactory and RedisTemplate Bean definitions omitted

  @Bean
  public RedisMappingContext keyValueMappingContext() {
    return new RedisMappingContext(
      new MappingConfiguration(
        new MyKeyspaceConfiguration(), new IndexConfiguration()));
  }

  public static class MyKeyspaceConfiguration extends KeyspaceConfiguration {

    @Override
    protected Iterable<KeyspaceSettings> initialConfiguration() {
      return Collections.singleton(new KeyspaceSettings(Person.class, "persons"));
    }
  }
}

7.4. Secondary Indexes

Secondary indexes are used to enable lookup operations based on native Redis structures. Values are written to the according indexes on every save and are removed when objects are deleted or expire.

Given the sample Person entity we can create an index for firstname by annotating the property with @Indexed.

Example 13. Annotation driven indexing
@RedisHash("persons")
public class Person {

  @Id String id;
  @Indexed String firstname;
  String lastname;
  Address address;
}

Indexes are built up for actual property values. Saving two Persons eg. "rand" and "aviendha" results in setting up indexes like below.

SADD persons:firstname:rand e2c7dcee-b8cd-4424-883e-736ce564363e
SADD persons:firstname:aviendha a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56

It is also possible to have indexes on nested elements. Assume Address has a city property that is annotated with@Indexed. In that case, once person.address.city is not null, we have Sets for each city.

SADD persons:address.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e

Further more the programmatic setup allows to define indexes on map keys and list properties.

@RedisHash("persons")
public class Person {

  // ... other properties omitted

  Map<String,String> attributes;      
  Map<String Person> relatives;       
  List<Address> addresses;            
}
SADD persons:attributes.map-key:map-value e2c7dcee-b8cd-4424-883e-736ce564363e
SADD persons:relatives.map-key.firstname:tam e2c7dcee-b8cd-4424-883e-736ce564363e
SADD persons:addresses.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e
Indexes will not be resolved on References.

Same as with keyspaces it is possible to configure indexes without the need of annotating the actual domain type.

Example 14. Index Setup via @EnableRedisRepositories
@Configuration
@EnableRedisRepositories(indexConfiguration = MyIndexConfiguration.class)
public class ApplicationConfig {

  //... RedisConnectionFactory and RedisTemplate Bean definitions omitted

  public static class MyIndexConfiguration extends IndexConfiguration {

    @Override
    protected Iterable<IndexDefinition> initialConfiguration() {
      return Collections.singleton(new SimpleIndexDefinition("persons", "firstname"));
    }
  }
}
Example 15. Programmatic Index setup
@Configuration
@EnableRedisRepositories
public class ApplicationConfig {

  //... RedisConnectionFactory and RedisTemplate Bean definitions omitted

  @Bean
  public RedisMappingContext keyValueMappingContext() {
    return new RedisMappingContext(
      new MappingConfiguration(
        new KeyspaceConfiguration(), new MyIndexConfiguration()));
  }

  public static class MyIndexConfiguration extends IndexConfiguration {

    @Override
    protected Iterable<IndexDefinition> initialConfiguration() {
      return Collections.singleton(new SimpleIndexDefinition("persons", "firstname"));
    }
  }
}

7.5. Time To Live

Objects stored in Redis may only be valid for a certain amount of time. This is especially useful for persisting short lived objects in Redis without having to remove them manually when they reached their end of life. The expiration time in seconds can be set via @RedisHash(timeToLive=…​) as well as via KeyspaceSettings (see Keyspaces).

More flexible expiration times can be set by using the @TimeToLive annotation on either a numeric property or method. However do not apply @TimeToLive on both a method and a property within the same class.

Example 16. Expirations
public class TimeToLiveOnProperty {

  @Id
  private String id;

  @TimeToLive
  private Long expiration;
}

public class TimeToLiveOnMethod {

  @Id
  private String id;

  @TimeToLive
  public long getTimeToLive() {
  	return new Random().nextLong();
  }
}

The repository implementation ensures subscription to Redis keyspace notifications viaRedisMessageListenerContainer.

When the expiration is set to a positive value the according EXPIRE command is executed. Additionally to persisting the original, a phantom copy is persisted in Redis and set to expire 5 minutes after the original one. This is done to enable the Repository support to publish RedisKeyExpiredEvent holding the expired value via SpringsApplicationEventPublisher whenever a key expires even though the original values have already been gone. Expiry events will be received on all connected applications using Spring Data Redis repositories.

The RedisKeyExpiredEvent will hold a copy of the actually expired domain object as well as the key.

The keyspace notification message listener will alter notify-keyspace-events settings in Redis if those are not already set. Existing settings will not be overridden, so it is left to the user to set those up correctly when not leaving them empty.
Redis Pub/Sub messages are not persistent. If a key expires while the application is down the expiry event will not be processed which may lead to secondary indexes containing still references to the expired object.

7.6. Persisting References

Marking properties with @Reference allows storing a simple key reference instead of copying values into the hash itself. On loading from Redis, references are resolved automatically and mapped back into the object.

Example 17. Sample Property Reference
_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = al’thor
mother = persons:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56      
Reference stores the whole key (keyspace:id) of the referenced object.
Referenced Objects are not subject of persisting changes when saving the referencing object. Please make sure to persist changes on referenced objects separately, since only the reference will be stored. Indexes set on properties of referenced types will not be resolved.

7.7. Queries and Query Methods

Query methods allow automatic derivation of simple finder queries from the method name.

Example 18. Sample Repository finder Method
public interface PersonRepository extends CrudRepository<Person, String> {

  List<Person> findByFirstname(String firstname);
}
Please make sure properties used in finder methods are set up for indexing.
Query methods for Redis repositories support only queries for entities and collections of entities with paging.

Using derived query methods might not always be sufficient to model the queries to execute. RedisCallback offers more control over the actual matching of index structures or even custom added ones. All it takes is providing aRedisCallback that returns a single or Iterable set of id values.

Example 19. Sample finder using RedisCallback
String user = //...

List<RedisSession> sessionsByUser = template.find(new RedisCallback<Set<byte[]>>() {

  public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
    return connection
      .sMembers("sessions:securityContext.authentication.principal.username:" + user);
  }}, RedisSession.class);

Here’s an overview of the keywords supported for Redis and what a method containing that keyword essentially translates to.

Table 3. Supported keywords inside method names
Keyword Sample Redis snippet

And

findByLastnameAndFirstname

SINTER …:firstname:rand …:lastname:al’thor

Or

findByLastnameOrFirstname

SUNION …:firstname:rand …:lastname:al’thor

Is,Equals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

SINTER …:firstname:rand

7.8. Redis Repositories running on Cluster

Using the Redis repository support in a clustered Redis environment is fine. Please see the Redis Cluster section forConnectionFactory configuration details. Still some considerations have to be done as the default key distribution will spread entities and secondary indexes through out the whole cluster and its slots.

key type slot node

persons:e2c7dcee-b8cd-4424-883e-736ce564363e

id for hash

15171

127.0.0.1:7381

persons:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56

id for hash

7373

127.0.0.1:7380

persons:firstname:rand

index

1700

127.0.0.1:7379

Some commands like SINTER and SUNION can only be processed on the Server side when all involved keys map to the same slot. Otherwise computation has to be done on client side. Therefore it be useful to pin keyspaces to a single slot which allows to make use of Redis serverside computation right away.

key type slot node

{persons}:e2c7dcee-b8cd-4424-883e-736ce564363e

id for hash

2399

127.0.0.1:7379

{persons}:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56

id for hash

2399

127.0.0.1:7379

{persons}:firstname:rand

index

2399

127.0.0.1:7379

Define and pin keyspaces via `@RedisHash("{yourkeyspace}") to specific slots when using Redis cluster.

7.9. CDI integration

Instances of the repository interfaces are usually created by a container, which Spring is the most natural choice when working with Spring Data. There’s sophisticated support to easily set up Spring to create bean instances. Spring Data Redis ships with a custom CDI extension that allows using the repository abstraction in CDI environments. The extension is part of the JAR so all you need to do to activate it is dropping the Spring Data Redis JAR into your classpath.

You can now set up the infrastructure by implementing a CDI Producer for the RedisConnectionFactory andRedisOperations:

class RedisOperationsProducer {


  @Produces
  RedisConnectionFactory redisConnectionFactory() {

    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setHostName("localhost");
    jedisConnectionFactory.setPort(6379);
    jedisConnectionFactory.afterPropertiesSet();

    return jedisConnectionFactory;
  }

  void disposeRedisConnectionFactory(@Disposes RedisConnectionFactory redisConnectionFactory) throws Exception {

    if (redisConnectionFactory instanceof DisposableBean) {
      ((DisposableBean) redisConnectionFactory).destroy();
    }
  }

  @Produces
  @ApplicationScoped
  RedisOperations<byte[], byte[]> redisOperationsProducer(RedisConnectionFactory redisConnectionFactory) {

    RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
    template.setConnectionFactory(redisConnectionFactory);
    template.afterPropertiesSet();

    return template;
  }

}

The necessary setup can vary depending on the JavaEE environment you run in.

The Spring Data Redis CDI extension will pick up all Repositories available as CDI beans and create a proxy for a Spring Data repository whenever a bean of a repository type is requested by the container. Thus obtaining an instance of a Spring Data repository is a matter of declaring an @Injected property:

class RepositoryClient {

  @Inject
  PersonRepository repository;

  public void businessMethod() {
    List<Person> people = repository.findAll();
  }
}

A Redis Repository requires RedisKeyValueAdapter and RedisKeyValueTemplate instances. These beans are created and managed by the Spring Data CDI extension if no provided beans are found. You can however supply your own beans to configure the specific properties of RedisKeyValueAdapter and RedisKeyValueTemplate.

Appendixes

Appendix Document structure

Various appendixes outside the reference documentation.

Schema defines the schemas provided by Spring Data Redis.

Appendix A: Schema

Core schema

<?xml version="1.0" encoding="UTF-8"?>

<xsd:schema xmlns="http://www.springframework.org/schema/redis"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tool="http://www.springframework.org/schema/tool"
    targetNamespace="http://www.springframework.org/schema/redis"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified">

  <xsd:import namespace="http://www.springframework.org/schema/tool" schemaLocation="http://www.springframework.org/schema/tool/spring-tool.xsd"/>

  <xsd:annotation>
    <xsd:documentation><![CDATA[
Defines the configuration elements for the Spring Data Redis support.
Allows for configuring Redis listener containers in XML 'shortcut' style.
    ]]></xsd:documentation>
  </xsd:annotation>

  <xsd:element name="listener-container">
    <xsd:annotation>
      <xsd:documentation><![CDATA[
Container of Redis listeners. All listeners will be hosted by the same container.
      ]]></xsd:documentation>
      <xsd:appinfo>
        <tool:annotation>
          <tool:exports type="org.springframework.data.redis.listener.RedisMessageListenerContainer"/>
        </tool:annotation>
      </xsd:appinfo>
    </xsd:annotation>
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="listener" type="listenerType" minOccurs="0" maxOccurs="unbounded"/>
      </xsd:sequence>
      <xsd:attribute name="connection-factory" type="xsd:string" default="redisConnectionFactory">
        <xsd:annotation>
          <xsd:documentation><![CDATA[
A reference to the Redis ConnectionFactory bean.
Default is "redisConnectionFactory".
          ]]></xsd:documentation>
          <xsd:appinfo>
            <tool:annotation kind="ref">
              <tool:expected-type type="org.springframework.data.redis.connection.ConnectionFactory"/>
            </tool:annotation>
          </xsd:appinfo>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="task-executor" type="xsd:string">
        <xsd:annotation>
          <xsd:documentation><![CDATA[
A reference to a Spring TaskExecutor (or standard JDK 1.5 Executor) for executing
Redis listener invokers. Default is a SimpleAsyncTaskExecutor.
          ]]></xsd:documentation>
          <xsd:appinfo>
            <tool:annotation kind="ref">
              <tool:expected-type type="java.util.concurrent.Executor"/>
            </tool:annotation>
          </xsd:appinfo>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="subscription-task-executor" type="xsd:string">
        <xsd:annotation>
          <xsd:documentation><![CDATA[
A reference to a Spring TaskExecutor (or standard JDK 1.5 Executor) for listening
to Redis messages. By default reuses the 'task-executor' value.
          ]]></xsd:documentation>
          <xsd:appinfo>
            <tool:annotation kind="ref">
              <tool:expected-type type="java.util.concurrent.Executor"/>
            </tool:annotation>
          </xsd:appinfo>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="topic-serializer" type="xsd:string">
        <xsd:annotation>
          <xsd:documentation><![CDATA[
A reference to the RedisSerializer strategy for converting Redis channels/patterns to
serialized format. Default is a StringRedisSerializer.
          ]]></xsd:documentation>
          <xsd:appinfo>
            <tool:annotation kind="ref">
              <tool:expected-type type="org.springframework.data.redis.serializer.RedisSerializer"/>
            </tool:annotation>
          </xsd:appinfo>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="phase" type="xsd:string">
        <xsd:annotation>
          <xsd:documentation><![CDATA[
The lifecycle phase within which this container should start and stop. The lower
the value the earlier this container will start and the later it will stop. The
default is Integer.MAX_VALUE meaning the container will start as late as possible
and stop as soon as possible.
          ]]></xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:complexType name="listenerType">
    <xsd:attribute name="ref" type="xsd:string" use="required">
      <xsd:annotation>
        <xsd:documentation><![CDATA[
  The bean name of the listener object, implementing
  the MessageListener interface or defining the specified listener method.
  Required.
        ]]></xsd:documentation>
        <xsd:appinfo>
          <tool:annotation kind="ref"/>
        </xsd:appinfo>
      </xsd:annotation>
    </xsd:attribute>
    <xsd:attribute name="topic" type="xsd:string">
      <xsd:annotation>
        <xsd:documentation><![CDATA[
The topics(s) to which the listener is subscribed. Can be (in Redis terminology) a
channel or/and a pattern. Multiple values can be specified by separating them with
spaces. Patterns can be specified by using the '*' character.
        ]]></xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>
    <xsd:attribute name="method" type="xsd:string">
      <xsd:annotation>
        <xsd:documentation><![CDATA[
The name of the listener method to invoke. If not specified,
the target bean is supposed to implement the MessageListener
interface or provide a method named 'handleMessage'.
        ]]></xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>
    <xsd:attribute name="serializer" type="xsd:string">
      <xsd:annotation>
        <xsd:documentation><![CDATA[
A reference to the RedisSerializer strategy for converting Redis Messages to
listener method arguments. Default is a StringRedisSerializer.
        ]]></xsd:documentation>
        <xsd:appinfo>
          <tool:annotation kind="ref">
            <tool:expected-type type="org.springframework.data.redis.serializer.RedisSerializer"/>
          </tool:annotation>
        </xsd:appinfo>
      </xsd:annotation>
    </xsd:attribute>
  </xsd:complexType>

  <xsd:element name="collection">
    <xsd:annotation>
      <xsd:documentation><![CDATA[
Factory creating collections on top of Redis keys.
      ]]></xsd:documentation>
      <xsd:appinfo>
        <tool:annotation>
          <tool:exports type="org.springframework.data.redis.support.collections.RedisCollectionFactoryBean"/>
        </tool:annotation>
      </xsd:appinfo>
    </xsd:annotation>
    <xsd:complexType>
	  <xsd:attribute name="id" type="xsd:ID">
		<xsd:annotation>
			<xsd:documentation><![CDATA[
The name of the Redis collection.]]></xsd:documentation>
		</xsd:annotation>
	  </xsd:attribute>
      <xsd:attribute name="key" type="xsd:string" use="optional">
        <xsd:annotation>
          <xsd:documentation><![CDATA[
Redis key of the created collection. Defaults to bean id.
          ]]></xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="template" type="xsd:string" default="redisTemplate">
        <xsd:annotation>
          <xsd:documentation><![CDATA[
A reference to a RedisTemplate bean.Default is "redisTemplate".
          ]]></xsd:documentation>
          <xsd:appinfo>
            <tool:annotation kind="ref">
              <tool:expected-type type="org.springframework.data.redis.core.RedisTemplate"/>
            </tool:annotation>
          </xsd:appinfo>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="type" default="LIST" use="optional">
        <xsd:annotation>
          <xsd:documentation><![CDATA[
The collection type (default is list).
If the key exists, its type takes priority. The type is used to disambiguate the collection type (map vs properties) or
specify one in case the key is missing.]]></xsd:documentation>
        </xsd:annotation>
        <xsd:simpleType>
        	<xsd:restriction base="xsd:string">
        		<xsd:enumeration value="LIST"/>
        		<xsd:enumeration value="SET"/>
        		<xsd:enumeration value="ZSET"/>
        		<xsd:enumeration value="MAP"/>
        		<xsd:enumeration value="PROPERTIES"/>
        	</xsd:restriction>
        </xsd:simpleType>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

Appendix B: Command Reference

Supported commands

Table 4. Redis commands supported by RedisTemplate.
Command Template Support

APPEND

X

AUTH

X

BGREWRITEAOF

X

BGSAVE

X

BITCOUNT

X

BITOP

X

BLPOP

X

BRPOP

X

BRPOPLPUSH

X

CLIENT KILL

X

CLIENT GETNAME

X

CLIENT LIST

X

CLIENT SETNAME

X

CLUSTER SLOTS

-

COMMAND

-

COMMAND COUNT

-

COMMAND GETKEYS

-

COMMAND INFO

-

CONFIG GET

X

CONFIG RESETSTAT

X

CONFIG REWRITE

-

CONFIG SET

X

DBSIZE

X

DEBUG OBJECT

-

DEBUG SEGFAULT

-

DECR

X

DECRBY

X

DEL

X

DISCARD

X

DUMP

X

ECHO

X

EVAL

X

EVALSHA

X

EXEC

X

EXISTS

X

EXPIRE

X

EXPIREAT

X

FLUSHALL

X

FLUSHDB

X

GET

X

GETBIT

X

GETRANGE

X

GETSET

X

HDEL

X

HEXISTS

X

HGET

X

HGETALL

X

HINCRBY

X

HINCRBYFLOAT

X

HKEYS

X

HLEN

X

HMGET

X

HMSET

X

HSCAN

X

HSET

X

HSETNX

X

HVALS

X

INCR

X

INCRBY

X

INCRBYFLOAT

X

INFO

X

KEYS

X

LASTSAVE

X

LINDEX

X

LINSERT

X

LLEN

X

LPOP

X

LPUSH

X

LPUSHX

X

LRANGE

X

LREM

X

LSET

X

LTRIM

X

MGET

X

MIGRATE

-

MONITOR

-

MOVE

X

MSET

X

MSETNX

X

MULTI

X

OBJECT

-

PERSIST

X

PEXIPRE

X

PEXPIREAT

X

PFADD

X

PFCOUNT

X

PFMERGE

X

PING

X

PSETEX

X

PSUBSCRIBE

X

PTTL

X

PUBLISH

X

PUBSUB

-

PUBSUBSCRIBE

-

QUIT

X

RANDOMKEY

X

RENAME

X

RENAMENX

X

RESTORE

X

ROLE

-

RPOP

X

RPOPLPUSH

X

RPUSH

X

RPUSHX

X

SADD

X

SAVE

X

SCAN

X

SCARD

X

SCRIPT EXITS

X

SCRIPT FLUSH

X

SCRIPT KILL

X

SCRIPT LOAD

X

SDIFF

X

SDIFFSTORE

X

SELECT

X

SENTINEL FAILOVER

X

SENTINEL GET-MASTER-ADD-BY-NAME

-

SENTINEL MASTER

-

SENTINEL MASTERS

X

SENTINEL MONITOR

X

SENTINEL REMOVE

X

SENTINEL RESET

-

SENTINEL SET

-

SENTINEL SLAVES

X

SET

X

SETBIT

X

SETEX

X

SETNX

X

SETRANGE

X

SHUTDOWN

X

SINTER

X

SINTERSTORE

X

SISMEMBER

X

SLAVEOF

X

SLOWLOG

-

SMEMBERS

X

SMOVE

X

SORT

X

SPOP

X

SRANDMEMBER

X

SREM

X

SSCAN

X

STRLEN

X

SUBSCRIBE

X

SUNION

X

SUNIONSTORE

X

SYNC

-

TIME

X

TTL

X

TYPE

X

UNSUBSCRIBE

X

UNWATCH

X

WATCH

X

ZADD

X

ZCARD

X

ZCOUNT

X

ZINCRBY

X

ZINTERSTORE

X

ZLEXCOUNT

-

ZRANGE

X

ZRANGEBYLEX

-

ZREVRANGEBYLEX

-

ZRANGEBYSCORE

X

ZRANK

X

ZREM

X

ZREMRANGEBYLEX

-

ZREMRANGEBYRANK

X

ZREVRANGE

X

ZREVRANGEBYSCORE

X

ZREVRANK

X

ZSCAN

X

ZSCORE

X

ZUNINONSTORE

X

Spring Boot集成Nacos配置中心避坑指南:命名空间、Data ID与刷新机制详解 配置中心是微服务架构中实现配置外置化与动态管理的核心组件,其本质是将传统application.yml的静态加载升级为运行时远程拉取+热更新机制。理解Nacos配置加载原理,关键在于掌握Spring Boot启动生命周期与Nacos客户端初始化时机的协同关系——从bootstrap阶段命名空间(Namespace)的硬编码隔离,到Data ID生成规则与Spring Profile的耦合逻辑,再到@RefreshScope代理触发的配置重绑定过程。这一技术链路直接决定配置是否生效、能否热更新、在Docker 阅读详情

相关推荐

spring-data-redis-1.7.2.RELEASE.jar

jedis、spring-redis-datade的整合使用,如果版本不匹配可能存在不兼容的问题,从而产生异常。 这里给出无异常的版本匹配: 1、spring-data-redis-1.7.2.RELEASE.jar 2、pring-data-commons-1.8.2.RELEASE.jar2 3、Spring4.3.2版本 这里先提供spring-data-redis-1.7.2.RELEASE.jar

python3.9 pytorch1.71. torchversion1.7.1 配置

#但是为什么我一直报错Solving environment: failed with initial frozen solve. Retrying with flexible solve.2.进入虚拟环境里,通过这个网址直接把torch 和 torch version下载下来,尝试了更换镜像源,更新conda,换网络,都不行。torch-version 成功!然后在官网里找到对应的命令行,然后复制到cmd里。3.把这两个文件粘贴在这个文件夹下,安装torch 成功!4.在torch171 环境里输入。

weixin_45068567的博客 1560

spring-data-redis-1.7.10.RELEASE jar包

Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis, JRedis, and RJC)进行了高度封装,RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅,并对spring 3.1 cache进行了实现。

Centos 6.x 升级docker 1.7.1 至 docker 1.13.0

前言 随着docker的不断升级,也提供更加丰富的功能,目前Centos6.x默认最新版本仅为Docker version 1.7.1, build 786b29d/1.7.1 该版本对于docker的监控功能少之极少,为了方便通过zabbix监控docker服务的性能,以下将docker升级至 1.13.0版本 环境 操作系统 : centos 6.7 docker版本:Do...

Hu_wen的专栏 2083

spring-data-redis-1.7.11.RELEASE.jar

在web项目中spring整合redis时使用的jar包

spring-data-redis-1.7.1.RELEASE

spring-data-redis-1.7.1.RELEASE

Redis

输入host、port(默认6379),点击OK。在客户端安装包进入终端。

masker_xue的博客 385

8台 × 8卡 910B NPU之顶尖大模型选型分析

本文对比了2026年主流大语言模型在昇腾910B NPU集群上的部署方案。重点评估了GLM5、MiniMax M2.5、Kimi K2.5、DeepSeek V3.2和Qwen 3.5旗舰版等候选模型,从部署需求(显存占用)、能力表现(基准测试、多模态支持)和NPU生态适配度三个维度进行分析。结果显示DeepSeek V3.2综合表现最优:支持BF16/W8A8/INT4量化,在4TB显存环境下可实现2000+ TPS,首token延迟<100ms,且具备官方NPU支持。备选方案Qwen 3.5旗舰版

FeelTouch Labs 756

redis从入门到入坑之3_配置文件详解

对于主要在linux上运行的软件或服务,对配置文件的配置是非常重要的,着和linux的特性有关,linux在加载软件或者服务的时候都是更具配置文件的加载,所以配置文件配置的是否优秀直接关系到该服务是否能够最大限度的发挥作用。 以下中文介绍大致内容都是翻译自他原来的英文(具体想知道那个配置项的作用,直接在本页面ctrl+f搜索即可) # Redis ...

m0_37852399的博客 654

Codex API 直接集成指南:告别中转代理,构建稳定高效的 AI 应用

在 AI 应用开发中,API 集成是连接模型能力与业务逻辑的核心环节。其基本原理是通过 HTTP 协议,按照服务提供商定义的规范发送请求并解析响应,实现远程调用。标准化的 API 设计确保了跨平台和跨语言的互操作性,其技术价值在于提供了稳定、可控且可扩展的服务接入方式,是构建企业级智能应用的基础。在实际应用场景中,开发者常需集成如 Codex 这类聚合了多种大语言模型的平台,以调用诸如 DeepSeek 等先进模型。然而,部分开发者仍依赖过时的第三方中转代理工具,这不仅引入了单点故障和版本锁定的风险,还可能

weixin_28224217的博客 339

Zenoh:统一数据平面协议,重塑物联网与边缘计算架构

在分布式系统与物联网领域,数据通信与处理常面临协议割裂的挑战。传统方案如MQTT、Kafka、gRPC等,分别针对发布/订阅、流处理和RPC等不同场景,导致架构复杂、集成成本高。其核心问题在于未能统一处理“运动中数据”(Data in Motion)与“静止中数据”(Data at Rest)。Zenoh协议通过创新的“Key-Value”寻址与“Selector”查询语言,将发布/订阅、存储、查询和计算四种核心操作融合进单一协议,构建了统一的抽象层。这种设计实现了极低的协议开销(仅5字节头部)和地理分布式

weixin_29597551的博客 290

spring data redis 和 redis高级版本对应关系

redis 3.x 4.x 5x等高级版本支持的spring客户端版本 spring data redis 2.2.x版本以上开始支持redis 3.x 4.x 5.x等高级版本,这里使用2.3.4.RELEASE版本 org.springframework.data spring-data-redis 2.3.4.RELEASE 其中对应的jedis版本3.3.0 见: https://github.com/spring-projects/spring-data-redis/bl

useProgram的博客 1万+

Qualcomm工具的使用

简介   由于我们公司主要是以高通平台为主,所以工具的使用是必不可少的,包括QPST、QRCT3、QXDM、QDART等。   高通工具顾名思义就是,对于高通平台的软件开发进行软件的烧录,软件的调试,软件的Log的抓取和分析过程,像我们平常用的大致就是烧版本、改NV、制作QCN、然后校准、强发强收等操作。 QPST   QPST主要是用来做一些参数的配置,包括EFS文件的编辑,QCN的导入和备份与...

Jimmy 2万+

java redis3.2,Java Springboot 整合redis(Springboot-Version:2.1.3.RELEASE)

环境准备添加redis依赖org.springframework.bootspring-boot-starter-data-redisredis.clientsjedis在application.properties中添加redis属性spring.redis.host=localhostspring.redis.port=6379#spring.redis.password=# 默认是0spri...

weixin_42175776的博客 229

地表最强之Android微信语音/腾讯会议通话录音

地表最强之Android微信语音/腾讯会议通话录音

cczhengv 6104

飞牛NAS1.1.19更新后SSH连不上?两步快速恢复连接

飞牛NAS1.1.19版本更新后SSH无法连接😟,实则是官方安全策略升级默认关闭了该服务,本文分享两步实操配置恢复SSH连接💻,还同步了官方的设备安全配置建议,帮助用户兼顾使用与设备防护🔒。

XiaoqiangClub的博客 2098

Spring Data Lovelace 正式发布

Spring Data的项目开发者Mark Paluch在博客宣布了Spring Data Lovelace 正式发布,本次大版本一共关闭了936个问题单。这个版本的火车构建在刚刚发布的Spring Framework 5.1 GA之上。您可以在下周的Spring Boot 2.1 M4版本中轻松使用Spring Data Lovelace。Sprin...

weixin_33841722的博客 387

SAP Fiori 从技术上而言到底包含哪些组件?

SAP Fiori是企业级UX设计的系统化解决方案,基于五大原则构建:角色导向(Role-based)、自适应(Adaptive)、简洁(Simple)、一致(Coherent)和愉悦(Delightful)。其技术实现包含SAPUI5开发框架、Fiori Launchpad统一入口、OData服务网关等核心组件,通过标准化设计模式与开发工具链,显著提升企业应用的用户体验和开发效率。典型案例显示,遵循Fiori原则可缩短30%以上的操作时长,降低50%的培训成本。该体系既保持跨设备一致性,又支持业务场景的深

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 223

关于redis有效期设置问题

redis服务器版本:3.0.7 项目引入jar包:spring-data-redis-1.6.1.RELEASE.jar,jedis-2.8.1.jar 使用redisTemplate遇到的一个问题,在此记录下: public String getIconResourceByCache (String model) { //先从缓存中获取数据 String hash

adsadadaddadasda的博客 4051

NSIS教程(6): 使用第三方插件

NSIS内置了很多指令,这些指令可以满足我们基本需求,但难免会遇到NSIS没有内置的功能,如进程操作,后台运行(即多线程),7z压缩等等,这个时候我们就需要借助第三方插件来满足我们所需要的功能了。 一、插件获取 NSIS官方收录插件的网址是:http://nsis.sourceforge.net/Category:Plugins,我们可以在这个网站上查找和下载我们需要的插件,该网站上针对每

while(1) { smile(); } 9万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Spring整合Redis(spring-data-redis)

maven依赖&lt;properties&gt; &lt;!-- redis 版本 --&gt; &lt;redis.version&gt;2.9.0&lt;/redis.version&gt; &lt;spring.redis.version&gt;1.8.4.RELEASE&lt;/spring.redis.version&gt; &lt;/properties&gt

萧曳丶 342

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Springboot整合Redis缓存

springboot提供了spring-data-redis的框架来整合redis的操作。下面主要介绍,springboot整合redis的配置,以及spring-data-redis是如何提供便捷的操作来处理redis。 1. redis环境准备在使用redis之前需要先安装redis数据库,具体的安装流程可以参考 http://blog.csdn.net/u011521890/article

u011521890的专栏 7920

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

redis报错redis/clients/jedis/JedisPoolConfig'(curren

redis + Jedis + Spring报错Type 'redis/clients/jedis/JedisPoolConfig'(current frame, stack[4]) is not aredis + Jedis + Spring集成之后运行报以下错误:log4j:WARNNo appenders could be found for logger(org.sp...

weixin_34037515的博客 877

spring-data-redis 用法

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34163553的博客 78

Spring Boot整合Redis认证失败:NOAUTH错误排查与修复指南

在现代分布式系统架构中,缓存技术是提升应用性能的关键组件,Redis作为高性能的内存数据库,其认证机制是保障数据安全的基础。Spring Boot通过自动配置简化了Redis客户端的集成,但在实际工程实践中,配置错误常导致连接认证失败。理解Spring Boot的配置加载优先级、Lettuce客户端的连接管理原理,以及Redis服务器的安全策略,对于构建稳定的生产环境至关重要。本文聚焦于Spring Boot与Redis整合时常见的“NOAUTH Authentication required”错误,通过分

weixin_30732487的博客 351

【springboot】万字操作指南 Spring Boot 2.x 升级到 3.x:微服务项目实战

摘要: 本文提供Spring Boot 2.x升级到3.x的实战指南,重点针对微服务项目。升级涉及JDK 17、Spring Framework 6、Jakarta EE等连锁变化,需系统规划版本矩阵(如Spring Boot 3.5.x + Spring Cloud 2025.0.x)。建议升级路线:先统一JDK 17环境,再处理依赖迁移(javax→jakarta)、Spring Security 6适配、OAuth2授权服务器改造等关键步骤。

Cjh20pan的博客 975
上一篇: 高可用的工作心得分享
下一篇: Spring-data-redis:特性与实例(redis 存储对象)
琅琊山二当家
博客等级 码龄18年 447粉丝 322原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值