In this tutorial, we will have a look at Redis, the key-value database or store. We’ll look at a couple of template implementations for storing data to and from a Redis database.

Spring framework is an open source Java platform that provides MVC infrastructure support for developing robust Java applications very easily and very rapidly using recommended MVC pattern.

Redis

Redis is driven by a key-store based data structure to persist the data and can be used as a database, cache and a message broker as well. To look at the main features:

It’s a NoSQL key-value data store.

Acts like a data structure server.

Redis can be used as a real database instead of just volatile cache.

The data types found in Redis are even more important. Key values can be simple strings, like we can do in memcached, but they can also be more complex types like Hashes, Lists (ordered collection, makes a great queue), Sets (unordered collection of non-repeating values), or Sorted Sets (ordered/ranked collection of non-repeating values).

Comparison with Memcache

Persistence to disk means you can use Redis as a real database instead of just a volatile cache. The data won't disappear when you restart, like with memcached.

Redis is a fantastic choice if we want a highly scalable data store shared by multiple processes, multiple applications, or multiple servers. As just an inter-process communication mechanism it is tough to beat. The fact that we can communicate cross-platform, cross-server, or cross-application just as easily makes it a pretty great choice for many many use cases. Its speed also makes it great as a caching layer.

Maven Dependencies

To start, let’s add suitable maven dependency for Redis in our project:

<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.8.1.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>

Clearly, we added Spring dependencies as well.

Configuring Redis

To start talking to a Redis Database, we need to create a connection using a Redis connection factory. There are, not one but four available options here:

JedisConnectionFactory JredisConnectionFactory LettuceConnectionFactory SrpConnectionFactory

Good thing about having four options is we can go for any option but the configuration remains surprisingly similar. For example, to define a bean for JedisConnectionFactory, we can do:

@Bean public RedisConnectionFactory redisCF() { JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); jedisConnectionFactory.setHostName("redis-server"); jedisConnectionFactory.setPort(7379); jedisConnectionFactory.setPassword("qwerty"); return jedisConnectionFactory; }

Each Redis connection factory have setHostName, setPort and setPassword methods.

Working with RedisTemplate

Redis connection factory produce connection to a Redis key-value store. Using RedisConnection, we can store and read data. Using the jedisConnectionFactory, a RedisTemplate is defined, which will then be used for querying data with a custom repository.

Let’s move on to define a RedisTemplate @Bean:

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

As with other Spring data projects, Spring Data Redis offers a high-level data access option with RedisTemplate, offering two templates:

RedisTemplate StringRedisTemplate

Constructing and Using RedisTemplate

We already saw how to construct a RedisTemplate bean. Something to notice is that it is parameterized with two types:

String: This signifies that the key of the data is a String. Object: Well, this can be any type of Object needed to be stored against a String key.

If both types turn out to be a String, we better use StringRedisTemplate. Once we have a RedisTemplate (or StringRedisTemplate), we can start saving, fetching, and deleting key-value entries.

Working with Simple values

Suppose that we want to save a User to a RedisTemplate<String, User> where the key is the value of the id property. The following snippet of code will do that via opsForValue():

redis.opsForValue().set(user.getId(), user);

Similarly, if we wanted to fetch a user whose id is 23, we could use this snippet:

User user = redis.opsForValue().get("23");

If no entry is found with the given key, null will be returned.

Working with Lists

Working with list values is simple via opsForList(). For example, we can add a value to the end of a list entry like this:

redis.opsForList().rightPush("users", user);







This adds a User to the end of the list stored at the key users.

>>> If a list doesn't already exist at that key, one will be created.

Whereas the rightPush() method adds an element to the end of a list entry, left- Push() inserts a value at the beginning:

redis.opsForList().leftPush("users", user);

There are a number of ways we can fetch an item from a list. We can pop an entry off of either end using leftPop() or rightPop():

User first = redis.opsForList().leftPop("users"); User last = redis.opsForList().rightPop("users");

Aside from fetching a value from the list, these two pop methods have the side effect of removing the popped items from the list. If we’d rather simply retrieve the value (perhaps even from the middle of the list), we can use the range() method:

List<User> users = redis.opsForList().range("users", 2, 12);







The range() method doesn’t remove any values from the list entry, but it does retrieve one or more values given the key and a range of indexes. The above example retrieves eleven entries starting with the entry at index 2 and going through index 12 (inclusive). If the range exceeds the bounds of the list, then only the entries within those indexes will be returned. If no entries fall within the indexes, an empty list will be returned.

Enough simple types thugh. What about our own Repository implementations like other Spring Data projects?

Redis Repository

To begin, let’s start by creating an entity which we will follow along with:

public class User implements Serializable { public enum Gender { MALE, FEMALE } private String id; private String name; private Gender gender; }

Spring Data Repository

As with other projects, let’s create our own UserRepository:

public interface UserRepository { void saveUser(User user); //Other methods }

It is worth noticing, unlike other Spring Data Repository interfaces, this is just a standard interface to define a required method. It doesn’t indicate any Spring-related features.

This is certainly unusual for a Spring Data project as well. Other Spring Data projects are enabled for building repositories based on the common Spring Data interfaces.

For instance, Spring Data JPA provides several base repository interfaces that we can extend to get base features such as 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 Repository Implementation

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

Redis supports different data structures such as 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 “User” as the name of the hash in which our User entities are stored.

@Repository public class UserRepositoryImpl implements UserRepository { private static final String KEY = "User"; private RedisTemplate<String, User> redisTemplate; private HashOperations hashOps; @Autowired privateUserRepositoryImpl(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } @PostConstruct private void init() { hashOps = redisTemplate.opsForHash(); } public void saveUser(User user) { hashOps.put(KEY, user.getId(), user); } public void updateUser(User user) { hashOps.put(KEY, user.getId(), user); } public User findUser(String id) { return (User) hashOps.get(KEY, id); } public Map<Object, Object> findAllUsers() { return hashOps.entries(KEY); } public void deleteUser(String id) { hashOps.delete(KEY, id); } }

That was pretty straightforward. Now quickly, let’s look at each CRUD operation.

User user = new User("123", "Liran", User.Gender.MALE); userRepository.saveUser(user);

Finding a user will be:

User retrievedUser = userRepository.findUser("123");

Let’s update a user now:

retrievedUser.setName(Hermoine"); userRepository.saveUser(retrievedUser);

Deleting a user will look like:

userRepository.deleteUser(user.getId());

Conclusion

In this tutorial, we went through the basics of Spring Data Redis.

No matter what kind of database we choose, fetching data from the database is a costly operation. In fact, database queries are often the biggest performance bottlenecks in any application.

Check out the homepage for more of the best SDK tools.