{"id":43998,"date":"2015-09-21T14:21:34","date_gmt":"2015-09-21T11:21:34","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=43998"},"modified":"2023-12-06T14:59:25","modified_gmt":"2023-12-06T12:59:25","slug":"spring-data-and-redis","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html","title":{"rendered":"Spring Data and Redis"},"content":{"rendered":"<p><em>This article is part of our Academy Course titled <a href=\"http:\/\/www.javacodegeeks.com\/2015\/09\/redis-a-nosql-key-value-store.html\">Redis a NoSQL key-value store<\/a>.<\/em><\/p>\n<p><em>This is a crash course on Redis. You will learn how to install Redis and start up the server. Additionally, you will mess around with the Redis command line. More advanced topics follow, such as replication, sharding and clustering, while the integration of Redis with Spring Data is also explained. Check it out <a href=\"http:\/\/www.javacodegeeks.com\/2015\/09\/redis-a-nosql-key-value-store.html\">here<\/a>!<\/em><\/p>\n<div class=\"toc\">\n<h4>Table Of Contents<\/h4>\n<dl>\n<dt><a href=\"#introduction\">1. Introduction<\/a><\/dt>\n<dt><a href=\"#Prerequisites\">2. Prerequisites<\/a><\/dt>\n<dt><a href=\"#PickingRedis\">3. Picking Redis Java client<\/a><\/dt>\n<dt><a href=\"#JavaAppDepend\">4. Java application dependencies and Eclipse<\/a><\/dt>\n<dt><a href=\"#ConfiguringStandalone\">5. Configuring Standalone Redis Over Spring Data Redis<\/a><\/dt>\n<dt><a href=\"#ConfiguringConnectionShared\">6. Configuring Connection to Sharded (partitioned) Redis<\/a><\/dt>\n<dt><a href=\"#ConfiguringConnectionRedis\">7. Configuring Connection to Redis Cluster<\/a><\/dt>\n<dt><a href=\"#AccessingRedis\">8. Accessing Redis using Spring Data Redis<\/a><\/dt>\n<dt><a href=\"#TransactionsRedis\">9. Transactions Using Spring Data Redis<\/a><\/dt>\n<dt><a href=\"#Pipelining\">10. Pipelining Using Spring Data Redis<\/a><\/dt>\n<dt><a href=\"#PublishSubscribe\">11. Publish\/Subscribe Using Spring Data Redis<\/a><\/dt>\n<dt><a href=\"#Conclusions\">12. Conclusions<\/a><\/dt>\n<\/dl>\n<\/div>\n<h2><a name=\"introduction\"><\/a>1. Introduction<\/h2>\n<p>Redis was created to solve real problems of real software systems. So far we have explored a very rich set of Redis features but we have not actually used any of them in real-world applications. To fill this gap, the last part of the tutorial is dedicated to present this topic. We are going to build a simple Java application which uses Redis and excellent <strong>Spring Data Redis<\/strong> (<a href=\"http:\/\/projects.spring.io\/spring-data-redis\/\">http:\/\/projects.spring.io\/spring-data-redis\/<\/a>) project together with <strong>Spring Framework<\/strong> (<a href=\"http:\/\/projects.spring.io\/spring-framework\/\">http:\/\/projects.spring.io\/spring-framework\/<\/a>) from <strong>Spring<\/strong> projects portfolio (<a href=\"http:\/\/spring.io\/\">http:\/\/spring.io\/<\/a>).  The latest released versions of <strong>Spring Data Redis<\/strong> and <strong>Spring Framework<\/strong> at the moment of writing are <strong>1.2.0<\/strong> and <strong>4.0.2<\/strong> respectively.<\/p>\n<p>Before diving into the details it worth mentioning that Redis supports wide variety of the application frameworks and programming languages. The complete list of the clients is available here: <a href=\"http:\/\/redis.io\/clients\">http:\/\/redis.io\/clients<\/a>.<\/p>\n<p>The rest of this tutorial assumes that a reader is able to program in Java and has basic familiarity <strong>Spring Framework<\/strong> (<a href=\"http:\/\/projects.spring.io\/spring-framework\/\">http:\/\/projects.spring.io\/spring-framework\/<\/a>).<\/p>\n<h2><a name=\"Prerequisites\"><\/a>2. Prerequisites<\/h2>\n<p>The usual toolset of Java developer includes JDK (Java Development Kit) and an IDE like <strong>Eclipse<\/strong> or <strong>Intellij IDEA<\/strong> to facilitate application development process. The latest version of JDK we will be using is <strong>1.7_51<\/strong> and can be downloaded from <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/index.html\">http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/index.html<\/a>. <\/p>\n<p>The choice of IDE would be <code>Eclipse<\/code>, the latest version of it is <strong>4.3.2<\/strong> and could be downloaded from <a href=\"https:\/\/www.eclipse.org\/downloads\/\">https:\/\/www.eclipse.org\/downloads\/<\/a> (any of <strong>Eclipse IDE for Java Developers<\/strong>, <strong>Eclipse IDE for Java EE Developers<\/strong> or <strong>Spring Tool Suite<\/strong> editions are good).<\/p>\n<h2><a name=\"PickingRedis\"><\/a>3. Picking Redis Java client<\/h2>\n<p>There are several Java clients available for use to access Redis from Java applications (all listed below are supported by <strong>Spring Data Redis<\/strong> as well):<\/p>\n<ul>\n<li>\tJedis: <a href=\"https:\/\/github.com\/xetorthio\/jedis\">https:\/\/github.com\/xetorthio\/jedis<\/a> <\/li>\n<li>\tJRedis: <a href=\"https:\/\/github.com\/alphazero\/jredis\">https:\/\/github.com\/alphazero\/jredis<\/a> <\/li>\n<li>\tlettuce: <a href=\"https:\/\/github.com\/wg\/lettuce\">https:\/\/github.com\/wg\/lettuce<\/a> <\/li>\n<\/ul>\n<p>From functionality prospective, all of them are quite similar but <strong>Jedis<\/strong> has gained more popularity and is widely used. That being said, <strong>Jedis<\/strong> would be a choice for our application as well. <\/p>\n<h2><a name=\"JavaAppDepend\"><\/a>4. Java application dependencies and Eclipse<\/h2>\n<p>The project we are going to build will introduce all the important Redis features we have discussed so far but from application developer prospective. We will start with basic example assuming there is a single standalone Redis instance up and running somewhere (let us refer to it as <code>redis-host<\/code>). Most of the scenarios are going to be presented as a small <strong>JUnit<\/strong> (<a href=\"http:\/\/junit.org\/\">http:\/\/junit.org\/<\/a>) test snippets.<\/p>\n<p>The de facto building and dependency management tool in Java world is still <strong>Apache Maven<\/strong> (<a href=\"http:\/\/maven.apache.org\/\">http:\/\/maven.apache.org\/<\/a>) and the version we are going to use is 3.1.1, downloadable from <a href=\"http:\/\/maven.apache.org\/docs\/3.1.1\/release-notes.html\">http:\/\/maven.apache.org\/docs\/3.1.1\/release-notes.html<\/a>.  We will not actually use Apache Maven too much letting Eclipse do this work on our behalf but we are going to look on basic dependency description file which by convention is called <code>pom.xml<\/code>.<\/p>\n<pre class=\"brush:xml\">\n&lt;project \n    xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" \n    xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n    xsi:schemaLocation=\"\n        http:\/\/maven.apache.org\/POM\/4.0.0 \n        http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;\n    &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n\n    &lt;groupId&gt;com.javacodegeeks&lt;\/groupId&gt;\n    &lt;artifactId&gt;redis&lt;\/artifactId&gt;\n    &lt;version&gt;0.0.1-SNAPSHOT&lt;\/version&gt;\n    &lt;packaging&gt;jar&lt;\/packaging&gt;\n\n    &lt;properties&gt;\n        &lt;project.build.sourceEncoding&gt;UTF-8&lt;\/project.build.sourceEncoding&gt;\n        &lt;spring.version&gt;4.0.2.RELEASE&lt;\/spring.version&gt;\n    &lt;\/properties&gt;\n\n    &lt;dependencies&gt;\n        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework.data&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-data-redis&lt;\/artifactId&gt;\n            &lt;version&gt;1.2.0.RELEASE&lt;\/version&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupId&gt;redis.clients&lt;\/groupId&gt;\n            &lt;artifactId&gt;jedis&lt;\/artifactId&gt;\n            &lt;version&gt;2.4.1&lt;\/version&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-core&lt;\/artifactId&gt;\n            &lt;version&gt;${spring.version}&lt;\/version&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-tx&lt;\/artifactId&gt;\n            &lt;version&gt;${spring.version}&lt;\/version&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-context&lt;\/artifactId&gt;\n            &lt;version&gt;${spring.version}&lt;\/version&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupId&gt;ch.qos.logback&lt;\/groupId&gt;\n            &lt;artifactId&gt;logback-classic&lt;\/artifactId&gt;\n            &lt;version&gt;1.0.13&lt;\/version&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-test&lt;\/artifactId&gt;\n            &lt;version&gt;${spring.version}&lt;\/version&gt;\n            &lt;scope&gt;test&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n        \n        &lt;dependency&gt;\n            &lt;groupId&gt;org.hamcrest&lt;\/groupId&gt;\n            &lt;artifactId&gt;hamcrest-all&lt;\/artifactId&gt;\n            &lt;version&gt;1.3&lt;\/version&gt;\n            &lt;scope&gt;test&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n              &lt;groupId&gt;com.jayway.awaitility&lt;\/groupId&gt;\n              &lt;artifactId&gt;awaitility&lt;\/artifactId&gt;\n              &lt;version&gt;1.5.0&lt;\/version&gt;\n              &lt;scope&gt;test&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupId&gt;junit&lt;\/groupId&gt;\n            &lt;artifactId&gt;junit&lt;\/artifactId&gt;\n            &lt;version&gt;4.11&lt;\/version&gt;\n            &lt;scope&gt;test&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n    &lt;\/dependencies&gt;\n\n    &lt;build&gt;\n        &lt;plugins&gt;\n            &lt;plugin&gt;\n                &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n                &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;\n                &lt;configuration&gt;\n                    &lt;source&gt;1.7&lt;\/source&gt;\n                    &lt;target&gt;1.7&lt;\/target&gt;\n                &lt;\/configuration&gt;\n            &lt;\/plugin&gt;\n        &lt;\/plugins&gt;\n    &lt;\/build&gt;\n&lt;\/project&gt;\n<\/pre>\n<p>If you are seasoned Java developer, <code>pom.xml<\/code> files should be very familiar for you. But for newcomers a few comments may be helpful. Basically, we declare that our project named <code>com.javacodegeeks.redis<\/code> depends on:<\/p>\n<ul>\n<li>\tJedis (<code>redis.clients.jedis<\/code>) <\/li>\n<li>\tSpring Data Redis (<code>org.springframework.data.spring-data-redis<\/code>) <\/li>\n<li>\tSpring Framework (<code>org.springframework.spring-core<\/code>, <code>org.springframework.spring-context<\/code>, <code>org.springframework.spring-tx<\/code>, <code>org.springframework.spring-test<\/code>) <\/li>\n<li>\tJUnit and accompanied test scaffolding (<code>junit.junit<\/code>, <code>org.hamcrest.hamcrest-all<\/code>, <code>com.jayway.awaitility.awaitility<\/code>) <\/li>\n<\/ul>\n<p>At this point we are able to import this <code>pom.xml<\/code> into <strong>Eclipse<\/strong> using Import (menu File -> Import \u2026) from <strong>Existing Maven Project<\/strong> feature.<\/p>\n<p><figure id=\"attachment_3628\" aria-describedby=\"caption-attachment-3628\" style=\"width: 652px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/09\/06.IMPORT-MAVEN-PROJECT.png\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/09\/06.IMPORT-MAVEN-PROJECT.png\" alt=\"Picture 1: Importing Existing Maven Projects into Eclipse.\" width=\"652\" height=\"571\" class=\"size-full wp-image-3628\" \/><\/a><figcaption id=\"caption-attachment-3628\" class=\"wp-caption-text\">Figure 1: Importing Existing Maven Projects into Eclipse<\/figcaption><\/figure><\/p>\n<p>When import is completed, the project called <code>com.javacodegeeks.redis<\/code> (or just <code>redis<\/code>, depending on your import settings) should appear inside Eclipse <strong>Project Explorer<\/strong> view.<\/p>\n<p><figure id=\"attachment_3627\" aria-describedby=\"caption-attachment-3627\" style=\"width: 472px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/09\/06.ECLIPSE-PROJECT-VIEW.png\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/09\/06.ECLIPSE-PROJECT-VIEW.png\" alt=\"Picture 2. Our com.javacodegeeks.redis inside Eclipse Project view. \" width=\"472\" height=\"475\" class=\"size-full wp-image-3627\" \/><\/a><figcaption id=\"caption-attachment-3627\" class=\"wp-caption-text\">Figure 2. Our <code>com.javacodegeeks.redis<\/code> inside Eclipse Project view<br \/><\/figcaption><\/figure><div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<h2><a name=\"ConfiguringStandalone\"><\/a>5. Configuring Standalone Redis Over Spring Data Redis<\/h2>\n<p>Redis configuration with Jedis starts from defining <code>JedisConnectionFactory<\/code>. By default, Jedis uses connection pool (<a href=\"http:\/\/en.wikipedia.org\/wiki\/Connection_pool\">http:\/\/en.wikipedia.org\/wiki\/Connection_pool<\/a>) in order not to create connections to the Redis server every time but rather borrow them from the pool of available connections. Overall it is considered as a good practice because the process of creating network connections is a relatively expensive operation.<\/p>\n<p>Let us define connection pool and connection factory as a separate <strong>Spring<\/strong> configuration bean so it could be imported by different application configurations independently.<\/p>\n<pre class=\"brush:java\">\npackage com.javacodegeeks.redis;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\n\nimport redis.clients.jedis.JedisPoolConfig;\nimport redis.clients.jedis.Protocol;\n\n@Configuration\npublic class ConnectionConfiguration  {\n    @Bean\n    public JedisPoolConfig poolConfig() {\n        final JedisPoolConfig jedisPoolConfig =  new JedisPoolConfig();         \n        jedisPoolConfig.setTestOnBorrow( true );\n        jedisPoolConfig.setMaxTotal( 10 );\n        return jedisPoolConfig;\n    }\n    \n    @Bean\n    public JedisConnectionFactory connectionFactory() {\n        final JedisConnectionFactory connectionFactory = \n            new JedisConnectionFactory( poolConfig() );     \n        connectionFactory.setHostName( \"redis-host\" );\n        connectionFactory.setDatabase( Protocol.DEFAULT_DATABASE );\n        connectionFactory.setPort( Protocol.DEFAULT_PORT );        \n        return connectionFactory;\n    }\n}\n<\/pre>\n<p>In this code snippet we are configuring the connection factory to Redis instance running on <code>redis-host<\/code> with a pool of maximum 10 connections. The <code>test on borrow<\/code> setting actually ensures that connection borrowed from the pool is still valid and can be used (otherwise the connection will be recreated).<\/p>\n<h2><a name=\"ConfiguringConnectionShared\"><\/a>6. Configuring Connection to Sharded (partitioned) Redis<\/h2>\n<p>In the <strong>part 4<\/strong>, <a href=\"http:\/\/www.javacodegeeks.com\/2015\/09\/redis-sharding\/\">Redis Sharding<\/a>, we talked about client-side partitioning. As a matter of fact, Jedis provides this capability but unfortunately <strong>Spring Data Redis<\/strong> does not support this functionality yet.<\/p>\n<h2><a name=\"ConfiguringConnectionRedis\"><\/a>7. Configuring Connection to Redis Cluster<\/h2>\n<p>In the <strong>part 5<\/strong>, <a href=\"http:\/\/www.javacodegeeks.com\/2015\/09\/redis-clustering\/\">Redis Clustering<\/a>, we discovered the clustering capability of Redis and mentioned that clients should support and recognize the changes in Redis protocol in order to issue the commands to right nodes. Jedis already provides support for Redis Cluster but unfortunately <strong>Spring Data Redis<\/strong> does not support this functionality yet.<\/p>\n<h2><a name=\"AccessingRedis\"><\/a>8. Accessing Redis using Spring Data Redis<\/h2>\n<p><strong>Spring Data Redis<\/strong> provides consistent and concise programming abstraction over different Redis clients (see please Picking Redis Java client). The core of this abstraction is the concept of the template:  the simplest way to provide the access to the required functionality without spending a lot of time writing boiler-plate code. In case of Redis, it is a <code>RedisTemplate<\/code>.<\/p>\n<p>From previous parts of this tutorial we know that Redis supports multiple primitive data types: strings and numbers. But Java type system is much richer than that and that is why <code>RedisTemplate<\/code> requires the type of the key and type of the value to operate on (and respectively serializers for those types). We will start with simple example where keys and values are just strings (in fact <strong>Spring Data Redis<\/strong> already includes such a class called <code>StringRedisTemplate<\/code> but let us look on a general concept nonetheless).<\/p>\n<pre class=\"brush:java\">\npackage com.javacodegeeks.redis;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\n@Configuration\n@Import( value = ConnectionConfiguration.class )\npublic class ApplicationConfiguration {\n    @Bean @Autowired\n    public RedisTemplate&lt; String, String &gt; redisTemplate( \n            final JedisConnectionFactory connectionFactory ) {        \n        final RedisTemplate&lt; String, String &gt; template = \n            new RedisTemplate&lt; String, String &gt;();        \n        template.setConnectionFactory( connectionFactory );\n        template.setKeySerializer( new StringRedisSerializer() );\n        template.setHashValueSerializer( new StringRedisSerializer() );\n        template.setHashKeySerializer( new StringRedisSerializer() );\n        template.setValueSerializer( new StringRedisSerializer() );\n        template.setStringSerializer( new StringRedisSerializer() );\n        return template;\n    }\n}\n<\/pre>\n<p>With that we are ready to write our first tests. The container for all test cases we are going to create is a class called <code>RedisStringsTestCase<\/code> which heavily uses the testing capabilities provided by <strong>Spring Test<\/strong> scaffolding.<\/p>\n<pre class=\"brush:java\">\npackage com.javacodegeeks.redis;\n\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.junit.Assert.assertThat;\n\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith( SpringJUnit4ClassRunner.class )\n@ContextConfiguration( classes = ApplicationConfiguration.class )\npublic class RedisStringsTestCase {\n    @Autowired private RedisTemplate&lt; String, String &gt; template;\n\n    \/\/ Out tests are going to be there    \n}\n<\/pre>\n<p>Mostly for every category of Redis commands (see please <strong>part 2<\/strong>, <a href=\"http:\/\/www.javacodegeeks.com\/2015\/09\/redis-commands-using-redis-command-line\/\">Redis Commands &#8211; Using Redis Command Line<\/a>), <code>RedisTemplate<\/code> has the fa\u00e7ade method which starts from \u2018<strong>ops<\/strong>\u2019 (opsForValue, opsForList, opsForHash, \u2026) which literally returns a one-to-one mapping of category-specific commands to Java method calls. The first test uses a <code>SET<\/code> command to store some key \/ value and immediately uses <code>GET<\/code> command to verify it is stored properly.<\/p>\n<pre class=\"brush:java\">\n@Test\npublic void testSetAndGet() {\n    template.opsForValue().set( \"mykey\", \"myvalue\" );\n    assertThat( template.opsForValue().get( \"mykey\"), equalTo( \"myvalue\" ) );\n}\n<\/pre>\n<p>To make sure test does not lie, we can check that <code>mykey<\/code> has value \u201c<strong>myvalue<\/strong>\u201d using <code>redis-cli<\/code> tool and connecting to <code>redis-host<\/code> instance.<\/p>\n<p><figure id=\"attachment_3629\" aria-describedby=\"caption-attachment-3629\" style=\"width: 700px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/09\/06.REDIS-GET.png\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/09\/06.REDIS-GET.png\" alt=\"Picture 3. Verifying that value for mykey was really stored on redis-host instance.\" width=\"700\" height=\"45\" class=\"size-full wp-image-3629\" \/><\/a><figcaption id=\"caption-attachment-3629\" class=\"wp-caption-text\">Figure 3. Verifying that value for <code>mykey<\/code> was really stored on <code>redis-host<\/code> instance<\/figcaption><\/figure><\/p>\n<p>Before moving to the next test cases, there is one issue to take into account: once the previous test finishes execution, the <code>mykey<\/code> will stay in Redis till someone deletes it. Such a behavior may cause other test cases to fail and usually is considered a bad practice. It would be nice to start every test with clean database and in fact we are going to make it work like that. The command which cleans current Redis database is <code>FLUSHDB<\/code>. It is not exposed by <code>RedisTemplate<\/code> directly but could be easily accessed and triggered by using <code>execute()<\/code> method and calling <code>flushDb()<\/code> on the underlying <code>RedisConnection<\/code>.<\/p>\n<pre class=\"brush:java\">\n@Before\npublic void setUp() {\n    template.execute( new RedisCallback&lt; Void &gt;() {\n        @Override\n        public Void doInRedis( RedisConnection connection ) throws DataAccessException {\n            connection.flushDb();\n            return null;\n        }\n    } );\n}\n<\/pre>\n<p>Next operation we are going to explore is <code>INCREMENT<\/code> command which demonstrates how transparent operations between strings and strings containing numbers are.<\/p>\n<pre class=\"brush:java\">\n@Test\npublic void testSetAndIncrementAndGet() {\n    template.opsForValue().set( \"mykey\", \"10\" );\n    template.opsForValue().increment( \"mykey\", 5 );\n    assertThat( template.opsForValue().get( \"mykey\"), equalTo( \"15\" ) );\n}\n<\/pre>\n<p>Simple enough, let us move on to more complex data structures: lists, sets and sorted sets. The first test case creates a list of values \u201c<strong>a<\/strong>\u201d, \u201c<strong>b<\/strong>\u201d, \u201c<strong>c<\/strong>\u201d, \u201c<strong>d<\/strong>\u201d (using <code>RPUSH<\/code> command). Then it checks the size of the list (<code>LLEN<\/code> command), asks for last element of the list by index (<code>LINDEX<\/code> command), and finally pops the first element from the list (<code>LPOP<\/code> command).<\/p>\n<pre class=\"brush:java\">\n@Test\npublic void testPushToListAndGetElementByIndexAndPopFirstElement() {\n    template.opsForList().rightPushAll( \"mykey\", \"a\", \"b\", \"c\", \"d\" );\n    assertThat( template.opsForList().size( \"mykey\" ), equalTo( 4L ) );\n    assertThat( template.opsForList().index( \"mykey\", 3 ), equalTo( \"d\" ) );\n    assertThat( template.opsForList().leftPop( \"mykey\" ), equalTo( \"a\" ) );\n    assertThat( template.opsForList().size( \"mykey\"), equalTo( 3L ) );\n} \n<\/pre>\n<p>The code looks very compact and readable. Let us turn from lists to sets and the next test case creates a set of values \u201c<strong>a<\/strong>\u201d, \u201c<strong>b<\/strong>\u201d, \u201c<strong>c<\/strong>\u201d, \u201c<strong>d<\/strong>\u201d (using <code>SADD<\/code> command). Then it checks the size of the set (using <code>SCARD<\/code> command) and asks if \u201c<strong>c<\/strong>\u201d and \u201c<strong>e<\/strong>\u201d are the members of this set or not (using <code>SISMEMBER<\/code> command).<\/p>\n<pre class=\"brush:java\">\n@Test\npublic void testAddToSetAndCheckElementExists() {\n    template.opsForSet().add( \"mykey\", \"a\", \"b\", \"c\", \"d\" );\n    assertThat( template.opsForSet().size( \"mykey\" ), equalTo( 4L ) );\n    assertThat( template.opsForSet().isMember( \"mykey\", \"c\" ), equalTo( true ) );\n    assertThat( template.opsForSet().isMember( \"mykey\", \"e\" ), equalTo( false ) );\n}\n<\/pre>\n<p>The full power of sets shows up in inter-set operations:  intersection (<code>SINTER<\/code> command), union (<code>SUNION<\/code> command) and difference (<code>SDIFF<\/code> command). The following test case demonstrates that in action by applying these operations to two sets.<\/p>\n<pre class=\"brush:java\">\n@Test\npublic void testIntersetOperations() {\n    template.opsForSet().add( \"mykey1\", \"a\", \"b\", \"c\", \"d\" );\n    template.opsForSet().add( \"mykey2\", \"c\", \"d\", \"e\", \"f\" );\n       \n    assertThat( template.opsForSet().intersect( \"mykey1\", \"mykey2\" ), \n         equalTo( set( \"c\", \"d\" ) ) );\n        \n    assertThat( template.opsForSet().union( \"mykey1\", \"mykey2\" ), \n        equalTo( set( \"a\", \"b\", \"c\", \"d\",  \"e\", \"f\" ) ) );\n\n    assertThat( template.opsForSet().difference( \"mykey1\", \"mykey2\" ), \n        equalTo( set( \"a\", \"b\" ) ) );\n}\n<\/pre>\n<p>To finish up with the data collection types, we are going to cover sorted sets which are referred by <strong>Spring Data Redis<\/strong> as ZSets. The test case below creates a sorted set (<code>ZADD<\/code> command) and then asks Redis to return all the members sorted by scores from high to low (<code>ZREVRANGEBYSCORE<\/code> command with <code>WITHSCORE<\/code> option).<\/p>\n<pre class=\"brush:java\">\n@Test\npublic void testAddToSortedSetAndCheckElementsAreSortedByScore() {\n    template.opsForZSet().add( \"mykey\", \"a\", 6.15d );\n    template.opsForZSet().add( \"mykey\", \"b\", 9.95d );\n    template.opsForZSet().add( \"mykey\", \"c\", 8.45d );\n        \n    assertThat( template.opsForZSet().reverseRangeByScoreWithScores( \"mykey\", 0d, 10d ),\n        equalTo( \n           set( \n                ( TypedTuple&lt; String &gt; )new DefaultTypedTuple&lt; String &gt;( \"b\", 9.95d ), \n                ( TypedTuple&lt; String &gt; )new DefaultTypedTuple&lt; String &gt;( \"a\", 6.15d ), \n                ( TypedTuple&lt; String &gt; )new DefaultTypedTuple&lt; String &gt;( \"c\", 8.45d ) \n           ) \n        ) \n     );\n}\n<\/pre>\n<p>The code is a bit verbose due to required generic type conversions but generally is also simple and readable enough.<\/p>\n<p>Lastly, we are going to switch our attention to hashes. Redis hashes could be thought as a data objects in Java: a container of properties (or fields) and their values. The next test case creates a hash (using <code>HSET<\/code> command) with two properties (or fields), \u201c<strong>prop1<\/strong>\u201d and \u201c<strong>prop2<\/strong>\u201d. Then it verifies that all properties and their values are stored properly (using <code>HGETALL<\/code> command), deletes all properties (fields) from the hash (using <code>HDEL<\/code> command) and checks they are really deleted (using <code>HGET<\/code> command).<\/p>\n<pre class=\"brush:java\">\n@Test\npublic void testHashOperations() {\n    template.opsForHash().put( \"mykey\", \"prop1\", \"value1\"  );\n    template.opsForHash().put( \"mykey\", \"prop2\", \"value2\" );        \n        \n    assertThat( template.opsForHash().entries( \"mykey\" ), \n        equalTo( map( \"prop1\", \"value1\", \"prop2\", \"value2\" ) ) );\n\n    assertThat( template.opsForHash().get( \"mykey\", \"prop1\" ), \n        equalTo( ( Object )\"value1\" ) );\n        \n    template.opsForHash().delete( \"mykey\", \"prop1\", \"prop2\" );\n    assertThat( template.opsForHash().get( \"mykey\", \"prop1\" ), \n        equalTo( null ) );\n}\n<\/pre>\n<p>In this section we went over some basics of <strong>Spring Data Redis<\/strong> and got a good understanding how Redis commands are mapped to its API. The number of test cases we have developed just glanced over the rich set of <strong>Spring Data Redis<\/strong> features. In the next three sections we are going to look on advanced API patterns: transactions, pipelining and publish\/subscribe.<\/p>\n<h2><a name=\"TransactionsRedis\"><\/a>9. Transactions Using Spring Data Redis<\/h2>\n<p>Though Redis transactions support is somewhat limited, it is still a very useful feature to have when you need it. To show off how Spring Data Redis supports Redis transaction semantics, we are going to create a test cases which:<\/p>\n<ul>\n<li>\tassigns some values to two keys: <code>mykey1<\/code> (<code>SET<\/code> command) and <code>mykey2<\/code> (<code>SADD<\/code> command) <\/li>\n<li>\tverifies that member \u201c<strong>a<\/strong>\u201d is not in <code>mykey2<\/code> set (<code>SISMEMBER<\/code> command) <\/li>\n<li>\tstarts watching for a key <code>mykey1<\/code> (<code>WATCH<\/code> command) <\/li>\n<li>\tinitiates a transaction (<code>MULTI<\/code> command) <\/li>\n<li>\tincrements <code>mykey1<\/code> (<code>INCREMENT<\/code> command) <\/li>\n<li>\tadds new member \u201c<strong>b<\/strong>\u201d to the set <code>mykey2<\/code> (<code>SADD<\/code> command) <\/li>\n<li>\tcompletes the transaction by issuing the <code>EXEC<\/code> command <\/li>\n<\/ul>\n<pre class=\"brush:java\">\n@Test\npublic void testTransaction() {\n    template.opsForValue().set( \"mykey1\", \"10\" );                \n        \n    template.opsForSet().add( \"mykey2\", \"a\" );        \n    assertThat( template.opsForSet().isMember( \"mykey2\", \"b\"), equalTo( false ) );\n        \n    template.execute( new SessionCallback&lt; List&lt; Object &gt; &gt;() {\n        @SuppressWarnings(\"unchecked\")\n        @Override\n        public&lt; K, V &gt; List&lt;Object&gt; execute( final RedisOperations&lt; K, V &gt; operations )\n                throws DataAccessException {\n                \n            operations.watch( ( K )\"mykey1\" );\n            operations.multi();                          \n                \n            operations.opsForValue().increment( ( K )\"mykey1\", 5 );\n            operations.opsForSet().add( ( K )\"mykey2\", ( V )\"b\" );\n                \n            return operations.exec();\n        }\n    } );\n        \n    assertThat( template.opsForValue().get( \"mykey1\"), equalTo( \"15\" ) );\n    assertThat( template.opsForSet().isMember( \"mykey2\", \"b\"), equalTo( true ) );\n}\n<\/pre>\n<p>However we ignored the return value of template.execute() method call, it returns the result of each individual command. In our test case it would be <strong>15<\/strong> as the result of <code>INCREMENT<\/code> and <strong>1<\/strong> as the result of <code>SADD<\/code>. <\/p>\n<h2><a name=\"Pipelining\"><\/a>10. Pipelining Using Spring Data Redis<\/h2>\n<p>The way we access Redis mostly all the time is single command \/ response sequence: in order to send a new command, the client should wait for result of previous command to be returned by the Redis server. But there is way to send multiple commands to the server without waiting for the response at all and finally read all the responses in a single step. This technique is called <code>pipelining<\/code>.<\/p>\n<p>Redis supports pipelining since the very early releases, so whatever version you are running, it is possible to  use pipelining with Redis (for more details please look at <a href=\"http:\/\/redis.io\/topics\/pipelining\">http:\/\/redis.io\/topics\/pipelining<\/a>).<\/p>\n<p>Pipelining can significantly increase the performance of your application by reducing the network latency. But there is a catch:  while any client sends commands using pipelining technique, the server will be forced to queue the responses in memory. If there is a need to pipeline a huge amount of commands, it is better to send these commands up to a given reasonable number (so to split them to multiple pipelines). The performance will be nearly the same but the additional memory used will be limited. <\/p>\n<p>The following test case demonstrates pipelining using <strong>Spring Data Redis<\/strong>. We are going to send 100 commands using pipelining and verify that all the commands have been sent off and processed by comparing the value of the counter with expected one.<\/p>\n<pre class=\"brush:java\">\n@Test\npublic void testPipelining() {\n    template.opsForValue().set( \"mykey1\", \"10\" );                \n                 \n    template.executePipelined( new RedisCallback&lt; Object &gt;() {\n        @Override\n        public Object doInRedis(RedisConnection connection) throws DataAccessException {\n            for( int i = 0; i &lt; 100; ++i ) {\n                template.opsForValue().increment( \"mykey1\", 1 );\n            }\n            return null;\n        }\n    } );\n        \n    assertThat( template.opsForValue().get( \"mykey1\"), equalTo( \"110\" ) );\n}\n<\/pre>\n<p>As with Redis transaction test case, we ignored the return value of <code>template.executePipelined()<\/code> method call but it returns the result of each individual command (in total of 100 results). Also, if you are wondering why we return <strong>null<\/strong> from <code>RedisCallback<\/code>, there is reason: this return value will be overridden by actual value from the response (when received) and as such the callback it not allowed to return <strong>non-null<\/strong> value (please refer to <a href=\"http:\/\/docs.spring.io\/spring-data\/data-redis\/docs\/1.2.0.RELEASE\/reference\/html\/redis.html#pipeline\">http:\/\/docs.spring.io\/spring-data\/data-redis\/docs\/1.2.0.RELEASE\/reference\/html\/redis.html#pipeline<\/a> for more details).<\/p>\n<h2><a name=\"PublishSubscribe\"><\/a>11. Publish\/Subscribe Using Spring Data Redis<\/h2>\n<p>Redis supports publish\/subscribe messaging paradigm and <strong>Spring Data Redis<\/strong> provides a full support for this feature as well. <\/p>\n<p>By nature, publish\/subscribe messaging involves at least two participants: publisher who publish the messages and subscriber who listens for a messages from the publisher (usually it is a many-to-many relationship but we have simplified it to single publisher \/ subscriber model). <\/p>\n<p>Developing a robust test case for that might look a bit tricky. Publishing is the easy part, but listening for a message on a particular channel (or pattern) requires some work to be done. We start with defining the subscriber class called <code>RedisMessageListener<\/code>. It will not do much but count all the messages it has received so far. <\/p>\n<pre class=\"brush:java\">\npackage com.javacodegeeks.redis;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.springframework.data.redis.connection.Message;\nimport org.springframework.data.redis.connection.MessageListener;\n\npublic class RedisMessageListener implements MessageListener {\n    private AtomicInteger count = new AtomicInteger( 0 ); \n    \n    @Override\n    public void onMessage(Message message, byte[] pattern) {\n        count.incrementAndGet();\n    }\n    \n    public int getCount() {\n        return count.get();\n    }\n}\n<\/pre>\n<p>Next, we should extend our configuration with additional beans for <code>RedisMessageListener<\/code> and <code>RedisMessageListenerContainer<\/code>. The role of the latter one is very important: it glues together listeners and the channels they are listening on. Here is the minimal configuration (<code>PubsubConfiguration<\/code>) required to let us get started (please notice that we are importing the <code>ApplicationConfiguration<\/code> created previously).<\/p>\n<pre class=\"brush:java\">\npackage com.javacodegeeks.redis;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.redis.connection.MessageListener;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\nimport org.springframework.data.redis.listener.ChannelTopic;\nimport org.springframework.data.redis.listener.RedisMessageListenerContainer;\n\n@Configuration\n@Import( value = ApplicationConfiguration.class )\npublic class PubsubConfiguration  {\n    @Bean @Autowired\n    public RedisMessageListenerContainer container( \n            final JedisConnectionFactory connectionFactory ) {        \n\n        final RedisMessageListenerContainer container = \n            new RedisMessageListenerContainer();\n        \n        container.setConnectionFactory( connectionFactory );\n        container.addMessageListener( listener(), new ChannelTopic( \"test-channel\" ) );\n        \n        return container;\n    }\n    \n    @Bean\n    public MessageListener listener() {\n        return new RedisMessageListener();\n    }\n}\n<\/pre>\n<p>To give a bit of context, we are attaching our listener to the channel called \u201c<strong>test-channel<\/strong>\u201d and that is the channel we are going to publish messages to.<\/p>\n<p>Publish \/ Subscribe messaging communications are inherently asynchronous and this is yet another complication in developing the test cases for such a feature. The subscribers will not receive messages immediately but with some delay. If you are connecting to the Redis server running on your local machine, it may take milliseconds but if you are accessing some instance on the cloud, it could take a while. One of the possible approaches to handle that is to introduce some kind of reasonable delay so to give the subscriber some time to receive all the messages (and this is the trick we are using in our test case as well).<\/p>\n<pre class=\"brush:java\">\npackage com.javacodegeeks.redis;\n\nimport static com.jayway.awaitility.Awaitility.await;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.junit.Assert.assertThat;\n\n\nimport java.util.concurrent.Callable;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith( SpringJUnit4ClassRunner.class )\n@ContextConfiguration( classes = PubsubConfiguration.class )\npublic class RedisPublishSubscriberTestCase {\n    @Autowired private RedisTemplate&lt; String, String &gt; template;\n    @Autowired private RedisMessageListener listener;\n    \n    @Test\n    public void testPublishSubscribe() {\n        assertThat( listener.getCount(), equalTo( 0 ) );\n        \n        template.convertAndSend( \"test-channel\", \"Test Message 1!\" );\n        template.convertAndSend( \"test-channel\", \"Test Message 2!\" );\n        template.convertAndSend( \"test-channel\", \"Test Message 3!\" );\n        \n        await().atMost( 1, SECONDS ).until(\n            new Callable&lt; Integer &gt;() {            \n                @Override\n                public Integer call() throws Exception {\n                    return listener.getCount();\n                }\n            }, \n            equalTo( 3 ) \n        );\n    }\n}\n<\/pre>\n<p>This new test cases is using our <code>PubsubConfiguration<\/code> class to instantiate the <strong>Spring<\/strong> test context. In the test case itself we are publishing three messages to the channel \u201c<strong>test-channel<\/strong>\u201d on the Redis server. Then we are giving some time (but no more than one second) to message listener to consume all the messages published on a channel. After that we are expecting the listener to receive all 3 messages and that is what we are validating at the end.<\/p>\n<h2><a name=\"Conclusions\"><\/a>12. Conclusions<\/h2>\n<p>Redis is evolving at a great pace. It is very hard to keep up with all its new features and commands. As such, you may find out that <strong>Spring Data Redis<\/strong> does not yet support some of the recent functionality available in latest Redis releases (even Java clients need some time to add the support for it). The good example is Redis Cluster which is not yet supported by <strong>Spring Data Redis<\/strong>.<\/p>\n<p>This is the last part of Redis tutorial but it it just a beginning of the journey to Redis world. If you would like to keep an eye on latest development happening in Redis, there are a couple of resources you may check out:<\/p>\n<ul>\n<li>\t<a href=\"http:\/\/antirez.com\/\">http:\/\/antirez.com\/<\/a>: the blog of Salvatore Sanfilippo, the creator of Redis <\/li>\n<li>\t<a href=\"http:\/\/aphyr.com\/posts\/283-call-me-maybe-redis\">http:\/\/aphyr.com\/posts\/283-call-me-maybe-redis<\/a>: very useful insights about  Redis Cluster availability <\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This article is part of our Academy Course titled Redis a NoSQL key-value store. This is a crash course on Redis. You will learn how to install Redis and start up the server. Additionally, you will mess around with the Redis command line. More advanced topics follow, such as replication, sharding and clustering, while the &hellip;<\/p>\n","protected":false},"author":141,"featured_media":223,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[113,117,321],"class_list":["post-43998","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-nosql","tag-redis","tag-spring-data"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Spring Data and Redis - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"This article is part of our Academy Course titled Redis a NoSQL key-value store. This is a crash course on Redis. You will learn how to install Redis and\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Spring Data and Redis - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"This article is part of our Academy Course titled Redis a NoSQL key-value store. This is a crash course on Redis. You will learn how to install Redis and\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2015-09-21T11:21:34+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-06T12:59:25+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Andrey Redko\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andrey Redko\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html\"},\"author\":{\"name\":\"Andrey Redko\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/771a6504862edc45322776832cbce413\"},\"headline\":\"Spring Data and Redis\",\"datePublished\":\"2015-09-21T11:21:34+00:00\",\"dateModified\":\"2023-12-06T12:59:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html\"},\"wordCount\":2683,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/redis-logo.jpg\",\"keywords\":[\"NoSQL\",\"Redis\",\"Spring Data\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html\",\"name\":\"Spring Data and Redis - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/redis-logo.jpg\",\"datePublished\":\"2015-09-21T11:21:34+00:00\",\"dateModified\":\"2023-12-06T12:59:25+00:00\",\"description\":\"This article is part of our Academy Course titled Redis a NoSQL key-value store. This is a crash course on Redis. You will learn how to install Redis and\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/redis-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/redis-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/spring-data-and-redis.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Spring Data and Redis\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/771a6504862edc45322776832cbce413\",\"name\":\"Andrey Redko\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"caption\":\"Andrey Redko\"},\"description\":\"Andriy is a well-grounded software developer with more then 12 years of practical experience using Java\\\/EE, C#\\\/.NET, C++, Groovy, Ruby, functional programming (Scala), databases (MySQL, PostgreSQL, Oracle) and NoSQL solutions (MongoDB, Redis).\",\"sameAs\":[\"http:\\\/\\\/aredko.blogspot.com\\\/\",\"http:\\\/\\\/ca.linkedin.com\\\/in\\\/aredko\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/andrey-redko\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Spring Data and Redis - Java Code Geeks","description":"This article is part of our Academy Course titled Redis a NoSQL key-value store. This is a crash course on Redis. You will learn how to install Redis and","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html","og_locale":"en_US","og_type":"article","og_title":"Spring Data and Redis - Java Code Geeks","og_description":"This article is part of our Academy Course titled Redis a NoSQL key-value store. This is a crash course on Redis. You will learn how to install Redis and","og_url":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2015-09-21T11:21:34+00:00","article_modified_time":"2023-12-06T12:59:25+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","type":"image\/jpeg"}],"author":"Andrey Redko","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Andrey Redko","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html"},"author":{"name":"Andrey Redko","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/771a6504862edc45322776832cbce413"},"headline":"Spring Data and Redis","datePublished":"2015-09-21T11:21:34+00:00","dateModified":"2023-12-06T12:59:25+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html"},"wordCount":2683,"commentCount":2,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","keywords":["NoSQL","Redis","Spring Data"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html","url":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html","name":"Spring Data and Redis - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","datePublished":"2015-09-21T11:21:34+00:00","dateModified":"2023-12-06T12:59:25+00:00","description":"This article is part of our Academy Course titled Redis a NoSQL key-value store. This is a crash course on Redis. You will learn how to install Redis and","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/redis-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/spring-data-and-redis.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Spring Data and Redis"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/771a6504862edc45322776832cbce413","name":"Andrey Redko","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","caption":"Andrey Redko"},"description":"Andriy is a well-grounded software developer with more then 12 years of practical experience using Java\/EE, C#\/.NET, C++, Groovy, Ruby, functional programming (Scala), databases (MySQL, PostgreSQL, Oracle) and NoSQL solutions (MongoDB, Redis).","sameAs":["http:\/\/aredko.blogspot.com\/","http:\/\/ca.linkedin.com\/in\/aredko"],"url":"https:\/\/www.javacodegeeks.com\/author\/andrey-redko"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/43998","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/141"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=43998"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/43998\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/223"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=43998"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=43998"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=43998"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}