1. What is Redis?

Redis is a database and a specialized language DSL written in ANSI C.

It follows the Server client model, listening to a TCP port and accepting commands.

Clients send command to Redis like

SET foo bar

or

LPUSH mylist val

Commands perform atomic operations on a key space, reading or altering the value of one or more keys.

No race condition will occur or any lock needed.

All the operations are performed by Redis on keys and values that are stored in the computer memory.

2. Redis main use case

  • Fast database for datasets that can fit memory, especially when there are a lot of writes to handle: real time statistics.
  • Caching: memcached alike usage but with ability to modify directly data on the Redis side instead of invalidate the cache.
  • Messaging: Redis lists are good queues, and Redis Pub/Sub allows for a more general messaging usage
  • Computational unit: using complex operations you can run computation into Redis instances to process data. For instance in order to run a recommendation engine.

3. Spring Data Redis main classes + Redis Connectors

Spring Redis integrates with Jedis, JRedis, SRP and Lettuce connectors.

There is only one set of APIs one needs to use that behaves consistently across different connectors.

RedisConnection and RedisConnectionFactory are used to work with active connections to Redis.

Also, RedisConnectionFactory handles the communication with the Redis back-end but also translates the library exceptions to Spring’s consistent DAO exception hierarchy so switching between connectors is achievable without any code changes.

4. Dependencies

Spring Data Redis comes with different connectors and the good thing is that as long as you code on the Spring Data Redis API the connector details do not matter to you. You can switch the connector on the fly by just changing the dependencies.

Example maven dependencies with Jedis connector:

<dependency>
    <groupid>org.springframework.data</groupid>
    <artifactid>spring-data-redis</artifactid>
    <version>1.6.0.RELEASE</version>
</dependency> 

<dependency>
    <groupid>redis.clients</groupid>
    <artifactid>jedis</artifactid>
    <version>2.5.2</version>
</dependency>

5. Basic configuration + Jedis connector example

Spring Boot Java configuration:

@Bean 
@ConditionalOnMissingBean 
public RedisConnectionFactory redisConnectionFactory() 
                                    throws UnknownHostException { 
    JedisConnectionFactory factory = 
                                new JedisConnectionFactory(); 
    factory.setHostName("localhost"); 
    factory.setPort(6379); 
    return factory; 
} 

@Bean 
@ConditionalOnMissingBean(name = "redisTemplate") 
public RedisOperations<Object, Object> redisTemplate(
                        RedisConnectionFactory redisConnectionFactory) 
                                 throws UnknownHostException { 
    RedisTemplate<Object, Object> template = new RedisTemplate<>(); 
    template.setConnectionFactory(redisConnectionFactory); 
    return template; 
} 

@Bean 
@ConditionalOnMissingBean(StringRedisTemplate.class) 
public StringRedisTemplate stringRedisTemplate(
                        RedisConnectionFactory redisConnectionFactory) 
                              throws UnknownHostException { 
    StringRedisTemplate template = new StringRedisTemplate(); 
    template.setConnectionFactory(redisConnectionFactory); 
    return template; 
} 

6. Basic Types Interaction

Some examples:

// ValueOperations, BoundValueOperations
stringRedisTemplate.opsForValue().set(key, value); 
stringRedisTemplate.boundValueOps(key).set(value); 

// HashOperations, BoundHashOperations
stringRedisTemplate.opsForHash().put(key, "hashKey", value); 
stringRedisTemplate.boundHashOps(key).put("hashKey", value); 

// ListOperations, BoundListOperations
stringRedisTemplate.opsForList().leftPush(key, value); 
stringRedisTemplate.opsForList().rightPush(key, value); 
stringRedisTemplate.opsForList().rightPop(key, 1, TimeUnit.SECONDS); 
stringRedisTemplate.opsForList().leftPop(key, 1, TimeUnit.SECONDS); 
stringRedisTemplate.boundListOps(key).leftPush(value); 
stringRedisTemplate.boundListOps(key).rightPush(value); 
stringRedisTemplate.boundListOps(key).rightPop(1, TimeUnit.SECONDS); 
stringRedisTemplate.boundListOps(key).leftPop(1, TimeUnit.SECONDS); 

// ZSetOperations, BoundZSetOperations
stringRedisTemplate.opsForZSet().add(key, "player1", 12.0d); 
stringRedisTemplate.opsForZSet().add(key, "player2", 11.0d); 
stringRedisTemplate.boundZSetOps(key).add("player1", 12.0d); 
stringRedisTemplate.boundZSetOps(key).add("player2", 11.0d);

7. Custom Type RedisTemplate<String, Person>

Here I am using a custom object as value using a JSON serializer :

public class Person { 
    private String firstName; 
    private String lastName; 
    ...
    // getters/setters are omitted 
} 
@Bean 
public RedisTemplate<String, Person> getPersonRedisTemplate(
                 RedisConnectionFactory redisConnectionFactory) { 
    RedisTemplate<String, Person> t = new RedisTemplate<>(); 
    t.setConnectionFactory(redisConnectionFactory); 
    t.setKeySerializer(new StringRedisSerializer()); 
    t.setValueSerializer(new Jackson2JsonRedisSerializer<>(Person.class)); 
    t.afterPropertiesSet(); 
    return t; 
} 
public class ExampleRepository { 

    @Autowired 
    private RedisTemplate<String, Person> personRedisTemplate; 

    public void savePerson(Person aPerson) { 
        personRedisTemplate.boundListOps("people").rightPush(aPerson); 
    } 

    public List<Person> getPeople() { 
        return personRedisTemplate.boundListOps("people").range(0, -1); 
    } 
} 

8. Support Classes

Spring Data Redis offers various reusable components such as atomic counters and collections.

The atomic counters make it easy to wrap Redis key incrementation while the collections allow easy management of Redis keys:

Atomic counter example

@Bean 
public RedisAtomicInteger init(RedisConnectionFactory factory) { 
    return new RedisAtomicInteger("myCounter", factory); 
} 
public class Example { 

    @Autowired 
    private RedisAtomicInteger atomicInteger; 

    public void increment() { 
        atomicInteger.incrementAndGet(); 
    } 
} 

Redis Collections example

@Bean 
public Deque<String> queue(StringRedisTemplate redisTemplate) { 
    return new DefaultRedisList<>(
               redisTemplate.boundListOps("MY_KEY_FOR_QUEUE")); 
}
public class DequeExample { 

    @Resource(name = "queue") 
    private Deque<String> queue; 

    public void add(String value) { 
        queue.add(value); 
    } 

    public String getFirst() { 
        return queue.getFirst(); 
    } 

    public String getLast() { 
        return queue.getLast(); 
    } 
} 

9. Publish/Subscribe model

Spring Data Redis supports Publish subscribe model on a topic (e.x. “chat”)

public class MyMessageListener implements MessageListener { 

    public void handleMessage(String message) { 
        // handle incoming message 
    }

} 
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(
                               RedisConnectionFactory connectionFactory) { 
    RedisMessageListenerContainer container = 
                                new RedisMessageListenerContainer(); 
    container.setConnectionFactory(connectionFactory); 
    container.addMessageListener(
            new MessageListenerAdapter(new MyMessageListener()), 
            Collections.singletonList(new ChannelTopic("chat"))); 
    return container; 
} 
public class Example { 

    @Autowired 
    private StringRedisTemplate template; 

    public void send(String payload) { 
        template.convertAndSend("chat", payload); 
    } 
}