Spring Boot Redis

By Arvind Rai, August 01, 2018
This page will walk through Spring Boot Data Redis example. 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 Boot provides spring-boot-starter-data-redis for Redis dependencies. Redis connections are obtained using LettuceConnectionFactory or JedisConnectionFactory. Lettuce and Jedis are Java Redis clients. Spring Boot 2.0 uses Lettuce by default. Spring Data provides RedisTemplate as the central class to interact with data in Redis store. To interact with string data, we can use string-focused extension StringRedisTemplate of RedisTemplate. Spring Data provides ListOperations, SetOperations, HashOperations etc to perform operations on Redis data and we can directly inject them in our Spring applications.

Technologies Used

Find the technologies being used in our example.
1. Java 9
2. Spring 5.0.7.RELEASE
3. Spring Boot 2.0.3.RELEASE
4. Maven 3.5.2
5. Eclipse Oxygen

Project Structure

Find the project structure of our demo application in Eclipse.
Spring Boot Redis

Maven File

Spring provides spring-boot-starter-data-redis to resolve Redis dependencies. It provides basic auto configurations for Lettuce and Jedis client libraries. By default Spring Boot 2.0 uses Lettuce. To get pooled connection factory we need to provide commons-pool2 dependency. Find the Maven file.
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-app</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>spring-boot-app</name>
	<description>Spring Boot Application</description>

	<parent>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>2.0.3.RELEASE</version>
	    <relativePath/>
	</parent>
	<properties>
	    <java.version>9</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.apache.commons</groupId>
	    <artifactId>commons-pool2</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> 

Using Lettuce Configurations

Spring Boot 2.0 starter spring-boot-starter-data-redis resolves Lettuce by default. Spring provides LettuceConnectionFactory to get connections. To get pooled connection factory we need to provide commons-pool2 on the classpath. To work with Lettuce we need following Maven dependencies.
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>		
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency> 
To configure Lettuce pool we need to use spring.redis.* prefix with Lettuce pool connection properties. Find the Lettuce pool sample configurations.
application.properties
spring.redis.host=localhost 
spring.redis.port=6379
spring.redis.password= 

spring.redis.lettuce.pool.max-active=7 
spring.redis.lettuce.pool.max-idle=7
spring.redis.lettuce.pool.min-idle=2
spring.redis.lettuce.pool.max-wait=-1ms  
spring.redis.lettuce.shutdown-timeout=200ms 
We can override default Redis host, port and password configurations. Use max-wait a negative value if we want to block indefinitely.

Using Jedis Configurations

By default Spring Boot 2.0 starter spring-boot-starter-data-redis uses Lettuce. To use Jedis we need to exclude Lettuce dependency and include Jedis. Find the Maven dependencies to use Jedis.
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <exclusions>
    <exclusion>
	 <groupId>io.lettuce</groupId>
	 <artifactId>lettuce-core</artifactId>
    </exclusion>
  </exclusions>		    
</dependency>		
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency> 
jedis dependency will automatically resolve commons-pool2 on the classpath.
To configure Jedis pool we need to use spring.redis.* prefix with Jedis pool connection properties. Find the Jedis pool sample configurations.
application.properties
spring.redis.host=localhost 
spring.redis.port=6379
spring.redis.password= 

spring.redis.jedis.pool.max-active=7 
spring.redis.jedis.pool.max-idle=7
spring.redis.jedis.pool.min-idle=2
spring.redis.jedis.pool.max-wait=-1ms 

ListOperations

ListOperations is used for Redis list specific operations. Find some of its 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 javax.annotation.Resource;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.stereotype.Repository;
import com.concretepage.Person;

@Repository
public class FriendDAO {
   private static final String KEY = "friendsKey";

   @Resource(name="redisTemplate")
   private ListOperations<String, Person> opsForList;	 	 
	  
   public void addFriend(Person person) {
	 opsForList.leftPush(KEY, person);
   }
   public long getNumberOfFriends() {
	 return opsForList.size(KEY);
   }
   public Person getFriendAtIndex(Integer index) {
	 return opsForList.index(KEY, index);
   }
   public void removeFriend(Person p) {
	 opsForList.remove(KEY, 1, p);
   }
} 
Person.java
package com.concretepage;
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;
        }
} 

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 com.concretepage.Person;

@Repository
public class FamilyDAO {
    private static final String KEY = "myFamilyKey";
	  
    @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);
    }	 
} 

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 com.concretepage.Person;

@Repository
public class EmployeeDAO {
    private static final String KEY = "employeesKey";
	  
    @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);
    }	  		  
} 

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. 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;

@Repository
public class UserDAO {
    private static final String KEY = "userKey";
	  
    @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);
    }	  
} 

RedisTemplate

RedisTemplate is the central class to interact with the data in Redis store. It performs automatic serialization and deserialization between the given objects and binary data stored in Redis. To inject RedisTemplate in our Spring Boot applications, we need to create RedisTemplate bean in JavaConfig as following.
RedisConfig.java
package com.concretepage;
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.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import com.concretepage.Person;

@Configuration
@ComponentScan("com.concretepage")
public class RedisConfig {
   @Bean
   public RedisConnectionFactory redisConnectionFactory() {
	LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
	return connectionFactory;
   }
   @Bean
   public RedisTemplate<String, Person> redisTemplate() {
	RedisTemplate<String, Person> redisTemplate = new RedisTemplate<>();
	redisTemplate.setConnectionFactory(redisConnectionFactory());
	return redisTemplate;
   }
} 
Now we can inject RedisTemplate in our DAO and can use it as following.
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 com.concretepage.Person;

@Repository
public class FriendDAO {
   private static final String KEY = "friendsKey";
	  
   @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);
   }
} 

Spring Boot Main Class

Here we are creating Spring Boot main class to execute the application and will test our DAO classes.
SpringBootAppStarter.java
package com.concretepage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.concretepage.dao.EmployeeDAO;
import com.concretepage.dao.FamilyDAO;
import com.concretepage.dao.FriendDAO;
import com.concretepage.dao.UserDAO;

@SpringBootApplication
public class SpringBootAppStarter implements CommandLineRunner {
    @Autowired
    private FriendDAO friendDAO;
    @Autowired	
    private FamilyDAO familyDAO;
    @Autowired	
    private EmployeeDAO empDAO;
    @Autowired	
    private UserDAO userDAO;
	
    public static void main(String[] args) throws Exception {
       SpringApplication.run(SpringBootAppStarter.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
       System.out.println("--Example of ListOperations--");
       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--");
       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--");
       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.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.  	   
    }
} 

Run Application

To test our 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. Download the project source code. Go to the root folder of the project using command prompt and run the command.
mvn spring-boot:run 

References

Spring Boot Reference Guide
Spring Data Redis Example

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI








©2023 concretepage.com | Privacy Policy | Contact Us