Spring Data Redis Example

By Arvind Rai, August 01, 2018
This page will walk through Spring Data Redis example. Spring Data provides API to perform Redis operations with ease. Redis is an open source, in memory data-structure store that can be used as database, cache and message broker. Redis supports data-structure such as strings, hashes, lists, sets etc. Redis is a NoSQL storage and uses key/value to store data. Spring Data provides different connection factories to get Redis connections. The example of connection factories are JedisConnectionFactory, LettuceConnectionFactory etc. In our example we will use JedisConnectionFactory. Jedis is a Java Redis client that is easy to use and small in size. Spring Data provides RedisTemplate to perform Redis operations. RedisTemplate has methods such as opsForList(), opsForSet(), opsForHash() etc that return ListOperations, SetOperations, HashOperations respectively. Most of the time we perform Redis operations with string datatype. So Spring Data has provided a string-focused extension as StringRedisTemplate that extends RedisTemplate. So StringRedisTemplate has all methods of RedisTemplate to perform Redis operations based on string datatype. In our example we will provide Spring Data and Redis configurations using JavaConfig as well as XML configurations with complete example.

Technologies Used

We are using following software in our example.
1. Java 8
2. Spring 4.3
3. Spring Data Redis 1.8.7.RELEASE
4. Gradle 3.3
5. Maven 3.3
6. Eclipse Mars

Gradle and Maven

For Spring Data Redis JAR dependency we need to use spring-boot-starter-data-redis. Find the Gradle and Maven file used in our example.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
archivesBaseName = 'Concretepage'
version = '1.0-SNAPSHOT' 
repositories {
    mavenCentral()
}
dependencies {
    compile  'org.springframework.boot:spring-boot-starter:1.5.7.RELEASE'
    compile  'org.springframework.boot:spring-boot-starter-data-redis:1.5.7.RELEASE'
} 
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.concretepage</groupId>
	<artifactId>spring-boot-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>spring-demo</name>
	<description>Spring Boot Demo Project</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.7.RELEASE</version>
	</parent>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
	    <dependency>
		 <groupId>org.springframework.boot</groupId>
		 <artifactId>spring-boot-starter</artifactId>
	    </dependency>
	    <dependency>
		 <groupId>org.springframework.boot</groupId>
		 <artifactId>spring-boot-starter-data-redis</artifactId>
	    </dependency>	
    	    <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-devtools</artifactId>
                 <optional>true</optional>
            </dependency> 
	</dependencies> 
	<build>
	   <plugins>
		<plugin>
	    	  <groupId>org.springframework.boot</groupId>
		  <artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	   </plugins>
	</build>
</project> 

RedisTemplate

RedisTemplate is the central class to interact with the Redis data. It performs automatic serialization and deserialization between the given objects and binary data stored in Redis. By default RedisTemplate uses Java serialization. This class is thread-safe once configured. RedisTemplate can be instantiated using different connection factory such as JedisConnectionFactory and LettuceConnectionFactory.
1. JedisConnectionFactory uses JedisPoolConfig for connection pooling.
2. LettuceConnectionFactory uses LettucePool for connection pooling. To work with Lettuce connector we need to add extra JAR .
For Gradle
compile  'biz.paluch.redis:lettuce:5.0.0.Beta1'
For Maven
<dependency>
    <groupId>biz.paluch.redis</groupId>
    <artifactId>lettuce</artifactId>
    <version>5.0.0.Beta1</version>
</dependency> 
In our example we will use JedisConnectionFactory to instantiate RedisTemplate. Jedis is a Java Redis client which is small in size and easy to use.
RedisTemplate has different methods for data operations. Find some of them.
1.
ValueOperations<K,V> opsForValue() 
opsForValue returns ValueOperations that performs operation on simple values.
2.
ListOperations<K,V> opsForList()
opsForList() returns ListOperations that performs operation on list values.
3.
SetOperations<K,V> opsForSet()
opsForSet() returns SetOperations that performs operation on set values.
4.
HashOperations<K,HK,HV> opsForHash()
opsForHash() returns HashOperations that performs operation on hash values.

If our most of the operation is string based then we can use StringRedisTemplate that is string-focused extension of RedisTemplate.

Redis Java Configuration

Here we will configure Spring Data with Redis using JavaConfig.
RedisConfig.java
package com.concretepage.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import com.concretepage.bean.Person;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
@ComponentScan("com.concretepage")
public class RedisConfig {
	@Bean
	public RedisConnectionFactory redisConnectionFactory() {
		JedisPoolConfig poolConfig = new JedisPoolConfig();
		poolConfig.setMaxTotal(5);
		poolConfig.setTestOnBorrow(true);
		poolConfig.setTestOnReturn(true);
		
		JedisConnectionFactory connectionFactory = new JedisConnectionFactory(poolConfig);
		connectionFactory.setUsePool(true);
		connectionFactory.setHostName("localhost");
		connectionFactory.setPort(6379);
		
		return connectionFactory;
	}
	@Bean
	public RedisTemplate<String, Person> redisTemplate() {
		RedisTemplate<String, Person> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(redisConnectionFactory());
		redisTemplate.setEnableTransactionSupport(true);
		return redisTemplate;
	}
	@Bean
	public StringRedisTemplate stringRedisTemplate() {
		StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(redisConnectionFactory());
		stringRedisTemplate.setEnableTransactionSupport(true);
		return stringRedisTemplate;
	}	
} 
JedisConnectionFactory uses host name as localhost and port as 6379 by default. To change these values use setHostName() and setPort() respectively. To enable/disable using of connection pool, we need to pass Boolean values to setUsePool() method.
RedisTemplate does not provide transaction support by default. To enable it we need to call its method
setEnableTransactionSupport(true)
We need to do same for StringRedisTemplate to enable transaction support.
We will create demo project using JavaConfig as well as XML configuration. Here find the demo project structure using JavaConfig.
Spring Data Redis Example

Redis XML Configuration

Here we will provide XML configuration for Spring Data with Redis. We will configure JedisConnectionFactory with connection pooling, RedisTemplate and StringRedisTemplate using XML configuration.
spring-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:context="http://www.springframework.org/schema/context"  
  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
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd">

  <context:component-scan base-package="com.concretepage" />
  
  <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"
       p:max-total="5" p:test-on-borrow="true" p:test-on-return="true"/>
  
  <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
       p:host-name="localhost" p:port="6379" p:use-pool="true">
          <constructor-arg ref="jedisPoolConfig"/>
  </bean>
  
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" 
       p:connection-factory-ref="jedisConnectionFactory" p:enable-transaction-support="true"/>
  
  <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" 
       p:connection-factory-ref="jedisConnectionFactory" p:enable-transaction-support="true"/>  
</beans> 
In our example we will create two demo project, one with JavaConfig and another with XML configuration. Here find the project structure using XML configuration.
Spring Data Redis Example

@Transactional Support

When we create any RedisTemplate bean then by default they will not support Spring @Transactional annotation. We need to enable it explicitly by calling setEnableTransactionSupport(true) for each and every RedisTemplate. We have also to enable transaction support for StringRedisTemplate explicitly by calling
setEnableTransactionSupport(true)
We enable transaction support using JavaConfig as following.
@Bean
public RedisTemplate<String, Person> redisTemplate() {
   RedisTemplate<String, Person> redisTemplate = new RedisTemplate<>();
   redisTemplate.setConnectionFactory(redisConnectionFactory());
   redisTemplate.setEnableTransactionSupport(true);
   return redisTemplate;
} 
Find the code snippet of XML configuration to enable transaction support.
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" 
       p:connection-factory-ref="jedisConnectionFactory" p:enable-transaction-support="true"/> 
Now we can use @Transactional as following.
@Repository
@Transactional
public class FriendDAO {
	------
}

ListOperations

It is used for Redis list specific operations. It is initialized as following.
@Autowired
private RedisTemplate<String, Person> redisTemplate;

ListOperations<String, Person> listOps = redisTemplate.opsForList(); 
We can also directly get the instance of ListOperations using javax.annotation.Resource annotation as following.
@Resource(name="redisTemplate")
ListOperations<String, Person> listOps;	 
Where redisTemplate is the name of RedisTemplate bean configured in JavaConfig or XML Configuration. Now find some of ListOperations methods.
leftPush(K key, V value): Prepends value to key.
rightPush(K key, V value): Appends value to key.
leftPop(K key): Removes and returns first element in list stored at key.
rightPop(K key): Removes and returns last element in list stored at key.
remove(K key, long count, Object value): Removes the first given number (count) of occurrences of value from the list stored at key.
index(K key, long index): Fetches element at index from list at key.
size(K key): Fetches the size of list stored at key.

Now find the example of ListOperations . Here we are performing create, read and delete operations.
FriendDAO.java
package com.concretepage.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.bean.Person;
@Repository
@Transactional
public class FriendDAO {
	  private static final String KEY = "friends";
	  
	  @Autowired
	  private RedisTemplate<String, Person> redisTemplate;
	  
	  public void addFriend(Person person) {
		  redisTemplate.opsForList().leftPush(KEY, person);
	  }
	  public long getNumberOfFriends() {
		  return redisTemplate.opsForList().size(KEY);
	  }
	  public Person getFriendAtIndex(Integer index) {
		  return redisTemplate.opsForList().index(KEY, index);
	  }
	  public void removeFriend(Person p) {
		  redisTemplate.opsForList().remove(KEY, 1, p);
	  }
}
Person.java
package com.concretepage.bean;
import java.io.Serializable;
public class Person implements Serializable {
	private static final long serialVersionUID = 1L;
	private int id;
	private String name;
	private int age;
	public Person() { }
	public Person(int id, String name, int age) {
		this.id = id;
		this.name = name;
		this.age = age;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String toString() {
                return id +" - " + name + " - " + age;
	}
        @Override
        public boolean equals(final Object obj) {
           if (obj == null) {
               return false;
           }
           final Person person = (Person) obj;
           if (this == person) {
               return true;
           } else {
               return (this.name.equals(person.name) && this.age == person.age);
           }  
        }
        @Override
        public int hashCode() {
           int hashno = 7;
           hashno = 13 * hashno + (name == null ? 0 : name.hashCode());
           return hashno;
        }
} 
Now we will test our FriendDAO.java. Find the code snippet.
System.out.println("--Example of RedisTemplate for ListOperations--");
FriendDAO friendDAO = context.getBean(FriendDAO.class);
Person p1 = new Person(1, "Mahesh", 30);
friendDAO.addFriend(p1);
Person p2 = new Person(2, "Krishna", 35);
friendDAO.addFriend(p2);
System.out.println("Number of friends: " + friendDAO.getNumberOfFriends());
System.out.println(friendDAO.getFriendAtIndex(1));
friendDAO.removeFriend(p2);
System.out.println(friendDAO.getFriendAtIndex(1)); //It will return null, because value is deleted. 
Output
--Example of RedisTemplate for ListOperations--
Number of friends: 2
1 - Mahesh - 30
null 


SetOperations

SetOperations performs Redis set specific operations. Find some of its methods.
add(K key, V... values): Adds values to set at key.
members(K key): Fetches all elements of set at key.
size(K key): Fetches size of set at key.
remove(K key, Object... values): Removes given values from set at key and returns the number of removed elements.

Now find the example of SetOperations. Here we will perform create, read and delete operations.
FamilyDAO.java
package com.concretepage.dao;
import java.util.Set;
import javax.annotation.Resource;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.bean.Person;
@Repository
@Transactional
public class FamilyDAO {
	  private static final String KEY = "myfamily";
	  
	  @Resource(name="redisTemplate")
	  private SetOperations<String, Person> setOps;	  
	  
	  public void addFamilyMembers(Person... persons) {
		  setOps.add(KEY, persons);  	
	  }
	  public Set<Person> getFamilyMembers() {
		  return setOps.members(KEY);
	  }
	  public long getNumberOfFamilyMembers() {
		  return setOps.size(KEY);
	  }
	  public long removeFamilyMembers(Person... persons) {
		  return setOps.remove(KEY, (Object[])persons);
	  }	 
}
Find the code snippet to test the above code.
System.out.println("--Example of SetOperations--");
FamilyDAO familyDAO = context.getBean(FamilyDAO.class);
Person p11 = new Person(101, "Ram", 30);
Person p12 = new Person(102, "Lakshman", 25);
Person p13 = new Person(103, "Bharat", 35);
familyDAO.addFamilyMembers(p11, p12, p13);
System.out.println("Number of Family members: " + familyDAO.getNumberOfFamilyMembers());
System.out.println(familyDAO.getFamilyMembers());
System.out.println("No. of Removed Family Members: " + familyDAO.removeFamilyMembers(p11, p12));
System.out.println(familyDAO.getFamilyMembers()); 
Output
--Example of SetOperations--
Number of Family members: 3
[101 - Ram - 30, 103 - Bharat - 35, 102 - Lakshman - 25]
No. of Removed Family Members: 2
[103 - Bharat - 35] 

HashOperations

HashOperations performs Redis map specific operations working on a hash. Find some of its methods.
putIfAbsent(H key, HK hashKey, HV value): Sets the value of a hash hashKey only if hashKey does not exist.
put(H key, HK hashKey, HV value): Sets the value of a hash hashKey.
get(H key, Object hashKey): Fetches value for given hashKey from hash at key.
size(H key): Fetches size of hash at key.
entries(H key): Fetches entire hash stored at key.
delete(H key, Object... hashKeys): Deletes given hash hashKeys at key.

Find the example of HashOperations with create, read, update and delete (CRUD) operations.
EmployeeDAO.java
package com.concretepage.dao;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.bean.Person;
@Repository
@Transactional
public class EmployeeDAO {
	  private static final String KEY = "employees";
	  
	  @Resource(name="redisTemplate")
	  private HashOperations<String, Integer, Person> hashOps;	 
	  
	  public void addEmployee(Person person) {
		  hashOps.putIfAbsent(KEY, person.getId(), person);
	  }
	  public void updateEmployee(Person person) {
		  hashOps.put(KEY, person.getId(), person);
	  }	  
	  public Person getEmployee(Integer id) {
		  return hashOps.get(KEY, id);
	  }
	  public long getNumberOfEmployees() {
		  return hashOps.size(KEY);
	  }
	  public Map<Integer, Person> getAllEmployees() {
		  return hashOps.entries(KEY);
	  }
	  public long deleteEmployees(Integer... ids) {
		  return hashOps.delete(KEY, (Object)ids);
	  }	  		  
} 
Find the code snippet to test above code.
System.out.println("--Example of HashOperations--");
EmployeeDAO empDAO = context.getBean(EmployeeDAO.class);
Person emp1 = new Person(11, "Ravan", 45);
Person emp2 = new Person(12, "Kumbhkarn", 35);
Person emp3 = new Person(13, "Vibhisan", 25);
empDAO.addEmployee(emp1);
empDAO.addEmployee(emp2);
empDAO.addEmployee(emp3);
System.out.println("No. of Employees: "+ empDAO.getNumberOfEmployees());
System.out.println(empDAO.getAllEmployees());
emp2.setAge(20);
empDAO.updateEmployee(emp2);
System.out.println(empDAO.getEmployee(12)); 
Output
--Example of HashOperations--
No. of Employees: 3
{13=13 - Vibhisan - 25, 11=11 - Ravan - 45, 12=12 - Kumbhkarn - 35}
12 - Kumbhkarn - 20 

StringRedisTemplate

StringRedisTemplate is the string-focused extension of RedisTemplate. Most of the time we perform Redis operations with string and hence Spring Data provides a dedicated template i.e. StringRedisTemplate. Here we will discuss opsForValue() method of StringRedisTemplate that will return ValueOperations.
@Autowired
private StringRedisTemplate stringRedisTemplate;

ValueOperations<String, String> valueOps = StringRedisTemplate.opsForValue(); 
Find some of ValueOperations methods.
setIfAbsent(K key, V value): Sets key to hold the string value if key is absent.
set(K key, V value): Sets value for key.
get(Object key): Fetches the value of key.

Now find the example of CRUD operations using StringRedisTemplate.
UserDAO.java
package com.concretepage.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository
@Transactional
public class UserDAO {
	  private static final String KEY = "user";
	  
	  @Autowired
	  private StringRedisTemplate stringRedisTemplate;
	  
	  public void addUserName(String uname) {
		  stringRedisTemplate.opsForValue().setIfAbsent(KEY, uname);
	  }
	  public void updateUserName(String uname) {
		  stringRedisTemplate.opsForValue().set(KEY, uname);
	  }	  
	  public String getUserName() {
		  return stringRedisTemplate.opsForValue().get(KEY);
	  }
	  public void deleteUser() {
		  stringRedisTemplate.delete(KEY);
	  }	  
} 
Find the code snippet to test the above code.
System.out.println("--Example of StringRedisTemplate--");
UserDAO userDAO = context.getBean(UserDAO.class);
userDAO.addUserName("sriram");
System.out.println(userDAO.getUserName());
userDAO.updateUserName("srikrishna");
System.out.println(userDAO.getUserName());
userDAO.deleteUser();
System.out.println(userDAO.getUserName()); //It will return null, because value is deleted. 
Output
--Example of StringRedisTemplate--
sriram
srikrishna
null 

Main Class to Run Application

Find the Main class used in our demo with JavaConfig to test Redis operations.
Main.java
package com.concretepage;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.concretepage.bean.Person;
import com.concretepage.config.RedisConfig;
import com.concretepage.dao.EmployeeDAO;
import com.concretepage.dao.FamilyDAO;
import com.concretepage.dao.FriendDAO;
import com.concretepage.dao.UserDAO;
public class Main {
	public static void main(String[] args) {
	   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
	   context.register(RedisConfig.class);
	   context.refresh();

	   System.out.println("--Example of RedisTemplate for ListOperations--");
           FriendDAO friendDAO = context.getBean(FriendDAO.class);
           Person p1 = new Person(1, "Mahesh", 30);
           friendDAO.addFriend(p1);
           Person p2 = new Person(2, "Krishna", 35);
           friendDAO.addFriend(p2);
	   System.out.println("Number of friends: " + friendDAO.getNumberOfFriends());
           System.out.println(friendDAO.getFriendAtIndex(1));
           friendDAO.removeFriend(p2);
           System.out.println(friendDAO.getFriendAtIndex(1)); //It will return null, because value is deleted.  

	   System.out.println("--Example of SetOperations--");
	   FamilyDAO familyDAO = context.getBean(FamilyDAO.class);
	   Person p11 = new Person(101, "Ram", 30);
	   Person p12 = new Person(102, "Lakshman", 25);
	   Person p13 = new Person(103, "Bharat", 35);
	   familyDAO.addFamilyMembers(p11, p12, p13);
	   System.out.println("Number of Family members: " + familyDAO.getNumberOfFamilyMembers());
           System.out.println(familyDAO.getFamilyMembers());
           System.out.println("No. of Removed Family Members: " + familyDAO.removeFamilyMembers(p11, p12));
           System.out.println(familyDAO.getFamilyMembers());

	   System.out.println("--Example of HashOperations--");
	   EmployeeDAO empDAO = context.getBean(EmployeeDAO.class);
	   Person emp1 = new Person(11, "Ravan", 45);
	   Person emp2 = new Person(12, "Kumbhkarn", 35);
	   Person emp3 = new Person(13, "Vibhisan", 25);
	   empDAO.addEmployee(emp1);
	   empDAO.addEmployee(emp2);
	   empDAO.addEmployee(emp3);
	   System.out.println("No. of Employees: "+ empDAO.getNumberOfEmployees());
	   System.out.println(empDAO.getAllEmployees());
	   emp2.setAge(20);
	   empDAO.updateEmployee(emp2);
	   System.out.println(empDAO.getEmployee(12));

           System.out.println("--Example of StringRedisTemplate--");
	   UserDAO userDAO = context.getBean(UserDAO.class);
           userDAO.addUserName("sriram");
           System.out.println(userDAO.getUserName());
           userDAO.updateUserName("srikrishna");
           System.out.println(userDAO.getUserName());
           userDAO.deleteUser();
           System.out.println(userDAO.getUserName()); //It will return null, because value is deleted.  	   
    }
} 

Test Application

To test our Spring Data and Redis demo application, find the steps given below.
1. Install and start Redis using the link.
2. If you are using Windows OS, you can install Cygwin first and then install Redis in it.
3. Redis will start on localhost at port 6379.
4. Now download source and run Main.java as Java Application.

Reference

Spring Data Redis

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us