Develop Spring Redis applications

Build Spring-based applications with Redis as the datastore

Redis is a key-value NoSQL datastore solution. Spring Data Redis is a Spring portfolio project that helps Java™ developers build Spring applications with Redis, without needing to work directly with the low-level Redis API. This article introduces Redis and then shows how to build a simple dictionary application by using the Spring Data Redis API.

Shekhar Gulati, Java developer, Freelance

Photo of Shekar GulatiShekhar Gulati is a Java developer who likes to spend time writing code and learning new technologies. He is an active speaker and writer who has presented at various conferences and written technical articles for developerWorks, Java Lobby, and Developer.com. You can read his blog and follow @shekhargulati on Twitter.



21 August 2013

Also available in Japanese

The open source Spring framework is a mainstay of enterprise application development, with millions of Java developers in its user ranks. Spring Data is an umbrella open source project that makes it easier to build Spring-powered applications that use data access technologies — including modern ones such as nonrelational databases, MapReduce frameworks, and cloud-based data services. One such technology is Redis (REmote DIctionary Server) — an open source, advanced, NoSQL key-value datastore that is written in ANSI C. In this article I introduce you to Redis, its data model and data types, and its advantages. Then, you'll see how to use Spring Data Redis to build a sample application.

Introducing Redis

Redis is an in-memory datastore that can also write to disk for durability. Redis can persist data in two ways: RDB and AOF. RDB persistence performs point-in-time snapshots of your data set at specified intervals. It's not very durable, and you might lose some data, but it is very fast. AOF persistence is much more durable and logs every write operation that the server receives. The write operations are reexecuted at server startup, reconstructing the original data set. When you query Redis, data is served from memory and never from disk, and Redis performs all operations on keys and values that are stored in memory.

Redis follows a client/server model whereby it listens to the TCP port and accepts commands. All the commands in Redis are atomic, so you can work with the same key from different clients without any race conditions. If you work with memcached (an in-memory object caching system) you will find that it is similar, but Redis is (so to speak) memcached++. (See Andrew Glover's "Java development 2.0: Redis for the real world" for a comparison between Redis and memcached.) Redis also supports data replication.

Data model

The Redis data model differs not only from a relational database management system (RDBMS) but also from any plain NoSQL key-value datastore. Redis data types resemble the foundational data types of programming languages and so feel natural to developers. Every data type supports operations applicable to its type. The supported data types are:

  • Strings
  • Lists
  • Sets
  • Sorted sets
  • Hashes

Key advantages

Redis' advantages lie in its speed, its support for rich data types, the atomicity of its operations, and its versatility:

  • Redis is exceptionally fast. It can perform about 100,000 SETs per second and about 100,000 GETs per second. You can use the redis-benchmark utility to benchmark its performance on your own machine. (redis-benchmark simulates SETs/GETs done by N clients at the same time that it sends M total queries.)
  • Native support in Redis for most of the data types that most developers already know makes it easy to solve various problems. Experience tells you which problem can be best handled by which data type.
  • Because all Redis operations are atomic, multiple clients concurrently accessing a Redis server all get the same updated value.
  • Redis is a multiutility tool that's useful for a number of use cases — caching, messaging-queues (Redis natively supports publish/subscribe), short-lived application data such as web sessions, web page hit counts, and more.

Getting started with Redis

To get started with Redis on Linux® or UNIX®, download the compressed .tar file (see Resources), extract it, and run the make command:

wget http://redis.googlecode.com/files/redis-2.6.7.tar.gz
tar xzf redis-2.6.7.tar.gz
cd redis-2.6.7
make

The compiled binary files are now available in the src directory. Run Redis with:

src/redis-server

Redis responds with the following output:

[988] 05 Jan 14:41:00.230 # Warning: no config file specified, using the default config. 
In order to specify a config file use src/redis-server /path/to/redis.conf 

[988] 05 Jan 14:41:00.231 * Max number of open files set to 10032
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 2.6.7 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in stand alone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 988
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               
[988] 05 Jan 14:41:00.238 # Server started, Redis version 2.6.7
[988] 05 Jan 14:41:00.239 * DB loaded from disk: 0.000 seconds
[988] 05 Jan 14:41:00.239 * The server is now ready to accept connections on port 6379

To interact with Redis by using the built-in client, launch the client from the command line:

src/redis-cli

This client session shows Redis responding to the ping and INFO commands:

redis 127.0.0.1:6379> ping
PONG
redis 127.0.0.1:6379> 
redis 127.0.0.1:6379> 
redis 127.0.0.1:6379> INFO
# Server
redis_version:2.6.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_mode:standalone
os:Darwin 12.0.0 x86_64
arch_bits:64
multiplexing_api:kqueue
gcc_version:4.2.1
process_id:3449
run_id:270454ebad19fbc851194548569efca6ac63e00a
tcp_port:6379
uptime_in_seconds:95
uptime_in_days:0
lru_clock:1407736
....

Redis data types by example

Now I'll briefly describe the data types that are supported by Redis and show you some simple examples that use the built-in client.

Strings

String is the basic data type that Redis supports. You can set a key's string value with the SET command, and you can get a key's string value with the GET command:

redis> SET firstname shekhar
OK
redis> SET lastname gulati
OK
redis> GET firstname
"shekhar"
redis> GET lastname
"gulati"

If the values of your keys are integers, then you can use DECR or DECRBY to decrement values and INCR or INCRBY to increment them. These operations are useful in scenarios in which you want to maintain a count of something — say, the number of hits for a web page:

redis> INCR votes
(integer) 1
redis> INCR votes
(integer) 2
redis> INCR votes
(integer) 3
redis> DECR votes
(integer) 2

Several other operations, including APPEND, GETRANGE, MSET, and STRLENGTH, are available for strings. See Resources for a link to the complete list of operations for all the Redis data types.

Lists

A list in Redis is an ordered collection of strings that you can add any number of (unique or nonunique) elements to. In addition to operations for adding elements to and getting elements from a list, Redis supports pop, push, range, and several other operations for lists.

Zero-based lists

In Redis, lists are zero-based.

As an example, suppose that you want to maintain a list of words (uniqueness doesn't matter) and get the three words that you added to the system most recently.

To add words to the list you can use the LPUSH command, which prepends one or more values to a list:

redis> LPUSH words austerity
(integer) 1
redis> LPUSH words socialism moratorium socialism socialism
(integer) 5

With LPUSH, the most recently added word goes to the top of the list, and the previously top word is pushed down. You can use the LRANGE command to view the top three words in the list:

redis> LRANGE words 0 2
1) "socialism"
2) "socialism"
3) "moratorium"

To get the length of a list you use the LLEN command:

redis > LLEN words
(integer) 5

To remove elements from a list, you use the LREM command. For example, use this command to remove all the occurrences of socialism:

redis> LREM words 0 socialism
(integer) 2

To delete the list, you must delete the words key:

redis 127.0.0.1:6379> DEL words
(integer) 1

Sets

Sets are unordered collections of unique elements. To add an element to a set, you use the SADD command; to get all the members of a set you use the SMEMBERS command. As an example, suppose that I want to maintain a collection (called uniquewords) of all unique words added in my system. As you can see, because I use SET I can't add the same word (socialism) twice:

redis> SADD uniquewords austerity
(integer) 1
redis> SADD uniquewords pragmatic
(integer) 1
redis> SADD uniquewords moratorium
(integer) 1
redis> SADD uniquewords socialism
(integer) 1
redis> SADD uniquewords socialism
(integer) 0

To view all the words in the uniquewords set, I use the SMEMBERS command:

redis 127.0.0.1:6379> SMEMBERS uniquewords
1) "moratorium"
2) "austerity"
3) "socialism"
4) "pragmatic"

You can also execute intersection and union commands on multiple sets. I'll create another set, called newwords, and add some elements to it:

redis 127.0.0.1:6379> SADD newwords austerity good describe strange
(integer) 4

To ascertain all the common elements in the two sets —uniquewords and newwords — I execute the SINTER command:

redis 127.0.0.1:6379> SINTER uniquewords newwords
1) "austerity"

To join multiple sets, you use the SUNION command. As you can see, the word austerity was added only once.

redis 127.0.0.1:6379> SUNION uniquewords newwords
1) "austerity"
2) "strange"
3) "describe"
4) "socialism"
5) "pragmatic"
6) "good"
7) "moratorium"

Sorted sets

Sorted sets are sets that can be sorted based on a score and that contain only unique elements. Each time that you add a value to the set, you provide a score that's used for sorting.

For example, suppose you want to sort a set of words based on their length. You use the ZADD command to add an element to a sorted set, by using the syntax ZADD key score value. You use the ZRANGE command to view the elements of a sorted set by score.

redis> ZADD wordswithlength 9 austerity
(integer) 1
redis> ZADD wordswithlength 7 furtive
(integer) 1
redis> ZADD wordswithlength 5 bigot
(integer) 1
redis> ZRANGE wordswithlength 0 -1
1) "bigot"
2) "furtive"
3) "austerity"

To get the size of a sorted set, you use ZCARD command:

redis 127.0.0.1:6379> ZCARD wordswithlength
(integer) 3

Hashes

Hashes allow you to store a key-value pair against a hash. This option can be useful in scenarios in which you want to save an object with several properties, as in this example:

redis> HSET user:1 name shekhar
(integer) 1
redis> HSET user:1 lastname gulati
(integer) 1
redis> HGET user:1
redis> HGET user:1 name
"shekhar"
redis> HGETALL user:1
1) "name"
2) "shekhar"
3) "lastname"
4) "gulati"

Now that you have a grasp on the Redis data types, you are ready to try to build an application by using the Spring Data Redis framework with Redis as the back-end datastore.


Developing a Spring Redis application

Prerequisites

To build this article's sample application, you need:

  • Redis
  • JDK 6 or above
  • Apache Maven 3 or above
  • Spring Tool Suite
  • Git

Using Spring Data Redis, Java developers can access Redis programmatically and perform operations. The Spring framework has always promoted a POJO (plain old Java object) based programming model with a strong emphasis on productivity, consistency, and portability. These values carry over to Spring Data Redis project.

Spring Data Redis provides an abstraction over the existing Redis client libraries such as Jedis, JRedis, redis-protocol, and RJC (see Resources). By eliminating the boilerplate code that is required for interacting with Redis, it makes it easy to work with Redis key-value datastores without needing to learn the low-level Redis API. It also provides a generified template class named RedisTemplate (similar to JDBCTemplate or HibernateTemplate) for interacting with Redis. RedisTemplate is the main class for object-oriented interaction with Redis. It handles object serialization and type conversion so that, as a developer, you work with objects and needn't worry about serialization and type conversion.

The application that you'll build is a simple dictionary application. (You can download the full code for the application from GitHub; see Resources.) A dictionary is a collection of words that can each have multiple meanings. The dictionary application can be easily modeled to the Redis list data type, with each word as the list key and the word's meanings as its value. (Or, instead of a list you can use a set if you want the meanings to be unique. You can use a sorted set if you want to sort the meanings.) For example, the word astonishing can be a key and astounding and staggering its values.

Begin by creating a simple word-meaning list. Start Redis with the redis-server command, and start the client with the redis-cli command. Then, execute the commands that are shown in this client session:

redis> RPUSH astonishing astounding
(integer) 1
redis> RPUSH astonishing staggering
(integer) 2
redis> LRANGE astonishing 0 -1
1) "astounding"
2) "staggering"

You created a list named astonishing and pushed the meanings astounding and staggering to the end of the astonishing list. And you used the LRANGE command to get all the meanings for astonishing.

Create a template project by using Spring Tool Suite

Now you must create a Spring template project so that you can use it for the application. Open Spring Tool Suite and go to File -> New -> Spring Template Project -> Simple Spring Utility Project ->. Click Yes when prompted. Enter dictionary as the project name and provide the top-level package name (mine is com.shekhar.dictionary). Now you have a sample project named dictionary in your Spring Tool Suite workspace.

Updating pom.xml with dependencies

The dictionary project has no dependencies that are related to the Spring Data Redis project. To add them, replace the pom.xml of the template project that you created with the pom.xml in Listing 1. (This file uses the Spring Data Redis project 1.0.2 release, the latest release as of this writing.)

Listing 1. Replacement pom.xml that adds Spring Data Redis dependencies
<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.shekhar</groupId>
   <artifactId>dictionary</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>dictionary</name>
   <url>http://maven.apache.org</url>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>

   <repositories>
      <repository>
         <id>spring-release</id>
         <name>Spring Maven RELEASE Repository</name>
         <url>http://maven.springframework.org/release</url>
      </repository>
   </repositories>
   <dependencies>
      <dependency>
         <groupId>javax.inject</groupId>
         <artifactId>javax.inject</artifactId>
         <version>1</version>
      </dependency>
      <dependency>
         <groupId>cglib</groupId>
         <artifactId>cglib</artifactId>
         <version>2.2.2</version>
      </dependency>
      <dependency>
         <groupId>org.springframework.data</groupId>
         <artifactId>spring-data-redis</artifactId>
         <version>1.0.2.RELEASE</version>
      </dependency>
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-test</artifactId>
         <version>3.1.2.RELEASE</version>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.8.1</version>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
               <source>1.6</source>
               <target>1.6</target>
            </configuration>
         </plugin>
      </plugins>
   </build>
</project>

Configuring RedisConnectionFactory and RedisTemplate

RedisConnectionFactory is a thread-safe connection factory for creating connections to Redis, and RedisConnection is a short-lived, non-thread-safe connection to Redis. RedisConnection provides one-to-one mapping with Redis commands, whereas RedisConnectionFactory provides convenience methods that helps eliminate boilerplate code. RedisConnectionFactory makes switching among the different Redis client APIs as easy as defining a bean. You'll use JedisConnectionFactory for the sample application, but you can use any of the other ConnectionFactory variants.

Create a LocalRedisConfig class, as shown in Listing 2:

Listing 2. Creating the LocalRedisConfig class
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.StringRedisTemplate;

import redis.clients.jedis.JedisPoolConfig;

@Configuration
@ComponentScan(basePackages="com.shekhar.dictionary.dao")
public class LocalRedisConfig {

@Bean
public RedisConnectionFactory jedisConnectionFactory(){
   JedisPoolConfig poolConfig = new JedisPoolConfig();
   poolConfig.maxActive = 10;
   poolConfig.maxIdle = 5;
   poolConfig.minIdle = 1;
   poolConfig.testOnBorrow = true;
   poolConfig.testOnReturn = true;
   poolConfig.testWhileIdle = true;
   JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
   return jedisConnectionFactory;
}

@Bean
public StringRedisTemplate redisTemplate(){
   StringRedisTemplate redisTemplate = new StringRedisTemplate(jedisConnectionFactory());
   return redisTemplate;
}
}

LocalRedisConfig defines JedisConnectionFactory and SpringRedisTemplate beans. SpringRedisTemplate is a specialized version of RedisTemplate for working with strings.

You can test the configuration by using a JUnit test, as shown in Listing 3:

Listing 3. Testing the configuration
import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(classes = LocalRedisConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class LocalRedisConfigTest {

   @Inject
   private JedisConnectionFactory jedisConnectionFactory;
   
   @Inject
   private StringRedisTemplate redisTemplate;
   
   @Test
   public void testJedisConnectionFactory() {
      assertNotNull(jedisConnectionFactory);
   }

   @Test
   public void testRedisTemplate() {
      assertNotNull(redisTemplate);
   }

}

Writing DictionaryDao

Now create a DictionaryDao class, as shown in Listing 4:

Listing 4. Creating the DictionaryDao class
import org.springframework.data.redis.core.StringRedisTemplate;

@Repository
public class DictionaryDao {

   private static final String ALL_UNIQUE_WORDS = "all-unique-words";
   
   private StringRedisTemplate redisTemplate;

   @Inject
   public DictionaryDao(StringRedisTemplate redisTemplate){
      this.redisTemplate = redisTemplate;
   }
   
   public Long addWordWithItsMeaningToDictionary(String word, String meaning) {
      Long index = redisTemplate.opsForList().rightPush(word, meaning);
      return index;
   }
}

You can use DictionaryDao to perform operations in Redis. As you can see in Listing 4, you inject RedisTemplate, the core class in the Spring Data Redis project, into DictionaryDao. StringRedisTemplate in Listing 4 is a child class of RedisTemplate for working with string data types.

RedisTemplate provides key-type operations such as ValueOperations, ListOperations, SetOperations, HashOperations, and ZSetOperations. Listing 4 uses ListOperations to store a new word in the Redis datastore. The rightPush() operation adds the word and its meaning to end of the list. The dictionaryDao.addWordWithItsMeaningToDictionary() method returns the index for the element that's added to the list.

Listing 5 shows a JUnit test case for dictionaryDao.addWordWithItsMeaningToDictionary():

Listing 5. Testing the dictionaryDao.addWordWithItsMeaningToDictionary() method
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.hasItems;

import java.util.List;
import java.util.Set;

import javax.inject.Inject;

import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.shekhar.dictionary.config.LocalRedisConfig;

@ContextConfiguration(classes = {LocalRedisConfig.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class DictionaryDaoTest {

   @Inject
   private DictionaryDao dictionaryDao;

   @Inject
   private StringRedisTemplate redisTemplate;

   @Test
   public void testAddWordWithItsMeaningToDictionary() {
      String meaning = "To move forward with a bounding, drooping motion.";
      Long index = dictionaryDao.addWordWithItsMeaningToDictionary("lollop",
            meaning);
      assertThat(index, is(notNullValue()));
      assertThat(index, is(equalTo(1L)));
   }

The first time you run this test it passes, and the word is stored in Redis. But if you then rerun the test it fails because Redis adds the same meaning again and returns 2 as its index. So, you must clean the Redis datastore after each run, by using either the flushAll() or the flushDb server command. The flushAll() command removes all keys from all databases, whereas as flushDb() removes keys from only the current database. Listing 6 shows the modified test:

Listing 6. Modified test for dictionaryDao.addWordWithItsMeaningToDictionary()
@ContextConfiguration(classes = {LocalRedisConfig.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class DictionaryDaoTest {

   @Inject
   private DictionaryDao dictionaryDao;

   @Inject
   private StringRedisTemplate redisTemplate;

   @After
   public void tearDown() {
      redisTemplate.getConnectionFactory().getConnection().flushDb();
   }

   @Test
   public void testAddWordWithItsMeaningToDictionary() {
      String meaning = "To move forward with a bounding, drooping motion.";
      Long index = dictionaryDao.addWordWithItsMeaningToDictionary("lollop",
            meaning);
      assertThat(index, is(notNullValue()));
      assertThat(index, is(equalTo(1L)));
   }

   @Test
   public void shouldAddMeaningToAWordIfItExists() {
      Long index = dictionaryDao.addWordWithItsMeaningToDictionary("lollop",
            "To move forward with a bounding, drooping motion.");
      assertThat(index, is(notNullValue()));
      assertThat(index, is(equalTo(1L)));
      index = dictionaryDao.addWordWithItsMeaningToDictionary("lollop",
            "To hang loosely; droop; dangle.");
      assertThat(index, is(equalTo(2L)));
   }
}

Now that you have the functionality for storing a word in the Redis datastore, the next step is to enable the functionality to get all of a word's meanings. You can handle this step easily by using List's range operation. The range() method takes three arguments: the name of the key, the range's start, and the range's end. To get all the meanings for a word, you can use 0 for the start end -1 for the end:

public List<String> getAllTheMeaningsForAWord(String word) {
      List<String> meanings = redisTemplate.opsForList().range(word, 0, -1);
      return meanings;
}

Another basic feature that you want in the application is the ability to delete a word. You can use the RedisTemplate class's delete for this purpose. The delete operation takes a collection of keys:

public void removeWord(String word) {
      redisTemplate.delete(Arrays.asList(word));
}

public void removeWords(String... words) {
      redisTemplate.delete(Arrays.asList(words));
}

JUnit test cases for the newly added read and delete operations are in Listing 7:

Listing 7. JUnit tests for the read and delete operations
@Test
   public void shouldGetAllTheMeaningForAWord() {
      setupOneWord();
      List<String> allMeanings = dictionaryDao
            .getAllTheMeaningsForAWord("lollop");
      assertThat(allMeanings.size(), is(equalTo(2)));
      assertThat(
            allMeanings,
            hasItems("To move forward with a bounding, drooping motion.",
                  "To hang loosely; droop; dangle."));
   }

   @Test
   public void shouldDeleteAWordFromDictionary() throws Exception {
      setupOneWord();
      dictionaryDao.removeWord("lollop");
      List<String> allMeanings = dictionaryDao
            .getAllTheMeaningsForAWord("lollop");
      assertThat(allMeanings.size(), is(equalTo(0)));
   }

   @Test
   public void shouldDeleteMultipleWordsFromDictionary() {
      setupTwoWords();
      dictionaryDao.removeWords("fain", "lollop");
      List<String> allMeaningsForLollop = dictionaryDao
            .getAllTheMeaningsForAWord("lollop");
      List<String> allMeaningsForFain = dictionaryDao
            .getAllTheMeaningsForAWord("fain");
      assertThat(allMeaningsForLollop.size(), is(equalTo(0)));
      assertThat(allMeaningsForFain.size(), is(equalTo(0)));
   }
}

Conclusion

This article introduced you to Redis and how to build Spring Redis applications with the Spring Data Redis project. I covered the basics of Redis, its data model, data types, and how to get started with Spring Redis. Redis includes plenty more to explore, including features such as Redis PubSub and MultI-EXEC. Check out this article's Resources for information on these topics.

Resources

Learn

Get products and technologies

Discuss

  • Get involved in the developerWorks community. Connect with other developerWorks users while you explore the developer-driven blogs, forums, groups, and wikis.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Java technology
ArticleID=940706
ArticleTitle=Develop Spring Redis applications
publish-date=08212013