If you have a few years of experience in the Java ecosystem, and you're interested in sharing that experience with the community (and getting paid for your work of course), have a look at the "Write for Us" page. Cheers. Eugen

I usually post about Persistence on Twitter - you can follow me there:

1. Overview

This article is an introduction to Spring Data Redis, which provides the abstractions of the Spring Data platform to Redis – the popular in-memory data structure store.

Redis is driven by a keystore-based data structure to persist data and can be used as a database, cache, message broker, etc.

We’ll be able to use the common patterns of Spring Data (templates, etc.), while also having the traditional simplicity of all Spring Data projects.

2. Maven Dependencies

Let’s start by declaring the Spring Data Redis dependencies in the pom.xml:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.6.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.5.1</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.2.2.RELEASE</version>
</dependency>

3. The Redis Configuration

Redis clients are used to define the connection settings between the application client and the Redis server instance.

There are number of Redis client implementations available for Java. In this tutorial, we’ll use Jedis – a simple and powerful Redis client implementation.

There is good support for both XML and Java configuration in the framework; for this tutorial, we’ll use Java-based configuration.

3.1. Java Configuration

Let’s start with the configuration bean definitions:

@Bean
JedisConnectionFactory jedisConnectionFactory() {
    return new JedisConnectionFactory();
}

@Bean
public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
    template.setConnectionFactory(jedisConnectionFactory());
    return template;
}

The configuration is quite simple. First, using the Jedis client, a Redis connectionFactory can be defined.

Using the jedisConnectionFactory, a RedisTemplate is defined, which will then be used for querying data with a custom repository.

3.2. Custom Connection Properties

You may have already noticed that the usual connection-related properties are missing in the above configuration. For example, the server address and port are missing in the configuration.The reason is simple:  for our example, we are using the defaults.

However, if you need to configure the connection details, you can always modify the jedisConnectionFactory configuration as follows:

@Bean
JedisConnectionFactory jedisConnectionFactory() {
    JedisConnectionFactory jedisConFactory = new JedisConnectionFactory();
    jedisConFactory.setHostName("localhost");
    jedisConFactory.setPort(6379);
    return jedisConFactory;
}

4. Redis Repository

Let’s use a Student entity for our examples.

public class Student implements Serializable {
  
    public enum Gender { 
        MALE, FEMALE
    }

    private String id;
    private String name;
    private Gender gender;
    private int grade;
    ...
}

4.1. The Spring Data Repository

Let’s now create the StudentRepository as follows:

public interface StudentRepository {
    
    void saveStudent(Student person);
    ...
}

Note that, unlike other Spring Data Repository interfaces, this is just a standard interface to define a supported method. It doesn’t enable any Spring-related features.

And this is certainly unusual for a Spring Data project. Most of the other Spring Data projects are capable of building repositories based on the common Spring Data interfaces.

For example, Spring Data JPA provides several base repository interfaces that you can extend to get base features such basic CRUD operations, the ability to generate queries based on method names, etc. In most cases, there’s no need to write an implementation of the repository interface at all.

Spring Data Redis, however, does not have base repository interfaces to extend, nor does it have method name-based query generation. This partly has to do with the team who works on Spring Data Redis simply not having enough time to work on it, and partly has to do with the fact that Redis does not support “queries” the way we typically think of them. You can read more in this StackOverflow answer by one of the maintainers of the Spring Data Redis project.

4.2. A Repository Implementation

The StudentRepositoryImpl implementation is using the redisTemplate defined in the Java configuration above.

Redis supports different data structures such as strings, hashes, lists, sets, and sorted sets. In this example we will use the opsForHash() function, which uses hash-related operations for data manipulation. We will use the string “Student” as the name of the hash in which our Student entities will be stored.

@Repository
public class StudentRepositoryImpl implements StudentRepository {

    private static final String KEY = "Student";
    
    private RedisTemplate<String, Student> redisTemplate;
    private HashOperations hashOps;

    @Autowired
    private StudentRepositoryImpl(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @PostConstruct
    private void init() {
        hashOps = redisTemplate.opsForHash();
    }
    
    public void saveStudent(Student student) {
        hashOps.put(KEY, student.getId(), student);
    }

    public void updateStudent(Student student) {
        hashOps.put(KEY, student.getId(), student);
    }

    public Student findStudent(String id) {
        return (Student) hashOps.get(KEY, id);
    }

    public Map<Object, Object> findAllStudents() {
        return hashOps.entries(KEY);
    }

    public void deleteStudent(String id) {
        hashOps.delete(KEY, id);
    }
}

The opsForHash() function returns the operations performed on hash values bound to the given key. It’s defined with three parameters: the key, the hash key, and the hash value type.

Just note that, in addition to opsForHash(), there are similar set-related, list-related, and simple value functions.

5. Data Access using StudentRepository

We have implemented the data accessing behaviors on the StudentRepositoryImpl class so that it can be used directly to persist data or manipulate persisted data.

5.1. Saving a New Student Object

Let’s save a new student object in data store:

Student student = new Student(
  "Eng2015001", "John Doe", Student.Gender.MALE, 1);
studentRepository.saveStudent(student);

5.2. Retrieving an Existing Student Object

We can verify the correct insertion of the student in the previous section by fetching the inserted student data:

Student retrievedStudent = 
  studentRepository.findStudent("Eng2015001");

5.3. Updating an Existing Student Object

Let’s change the name of the student retrieved above and save it again:

retrievedStudent.setName("Richard Watson");
studentRepository.saveStudent(student);

Finally you can retrieve the student’s data again and verify that the name is updated in the datastore.

5.4. Deleting an Existing Student Data

We can delete the above-inserted student data:

studentRepository.deleteStudent(student.getId());

Now we can search for the student object and verify that the result is null.

5.5. Find All Student Data

We can insert a few student objects:

Student engStudent = 
  new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1);
Student medStudent = 
  new Student("Med2015001", "Gareth Houston", Student.Gender.MALE, 2);
studentRepository.saveStudent(engStudent);
studentRepository.saveStudent(medStudent);

However this can also be done by inserting a Map object. For that, there is a different method – putAll() – which accepts a single Map object containing multiple student objects to be persisted.

To find all inserted students:

Map<Object, Object> retrievedStudents = 
  studentRepository.findAllStudents();

Then we can easily check the size of the retrievedStudents or verify for a greater granularity by checking the properties of the each object.

6. Conclusion

In this tutorial, we went through the basics of Spring Data Redis. The source code of the examples above can be found in a GitHub project.

I usually post about Persistence on Twitter - you can follow me there:


Sort by:   newest | oldest | most voted
prashanth-g
Guest

Can anyone help with an example for checking a key exists in RedisTemplate?

I am using redisTemplate.keys(“key”); to check whethre my key exists. Redis guys are telling not to use keys *

Eugen Paraschiv
Guest

So, skipping over the broader question of “should you use keys” – the RedisKeyCommands has a simple exists API you can use. Hope that helps.
Cheers,
Eugen.

Pramod Bhargava
Guest

There is a annotaion @EnableRedisRepository what it do?
how can i configure this in my configuration xml?

Grzegorz Piwowarek
Guest

This is a Spring Data annotation that pretty much connects all the wires between Redis and Java code. Is there any reason why you need to stick to XML and not to Java config?

Pramod Bhargava
Guest

My application is still using .xml configurations .so we dont have @configuration which comes with spring boot

Eugen Paraschiv
Guest

You’ll need to use some Java configuration to be able to use the annotation. However, keep in mind that moving to Java config is not an all or nothing choice. You can gradually make the move and still keep most of your XML configuration intact, and then slowly move that when you can.

Bartosz Jaszczak
Guest

I’ve got one question, is there a proper way to test Redis repositories/connections/entities? I’m using Spring Data Redis, and trying to write some tests for it. I’ve found projects like com.github.kstyrc.embedded-redis, but i dont like idea of alpha version of library with last commit 10 months ago in production dependencies. Should i use real/test redis instance? Is there any spring supported way to use embedded one? (I’ve moved my question from topic about client)

Eugen Paraschiv
Guest

I’ve never tried to run an embedded instance, so I’m not sure how stable/mature they are. I’ve always used an actual instance, but I’d be curious to know if there’s good embedded support as well.
Not much help on this one.
Cheers,
Eugen.

wpDiscuz