diff --git a/src/main/asciidoc/appendix/appendix-schema.adoc b/src/main/asciidoc/appendix/appendix-schema.adoc index c17f5fe78..fa3aa7311 100644 --- a/src/main/asciidoc/appendix/appendix-schema.adoc +++ b/src/main/asciidoc/appendix/appendix-schema.adoc @@ -1,11 +1,5 @@ [[appendix:schema]] [appendix] = Schema -:resourcesDir: ../../resources -== Core Schema - -[source,xml] -------------------------------------------- -include::{resourcesDir}/org/springframework/data/redis/config/spring-redis-1.0.xsd[] -------------------------------------------- +link:http://www.springframework.org/schema/redis/spring-redis-1.0.xsd[Spring Data Redis Schema (redis-namespace)] diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index ec30c3954..56d76afd4 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -2,7 +2,8 @@ Costin Leau, Jennifer Hickey, Christoph Strobl, Thomas Darimont, Mark Paluch, Jay Bryant :revnumber: {version} :revdate: {localdate} -:toc: left +:toc: +:toc-placement!: :spring-data-commons-include: ../../../../spring-data-commons/src/main/asciidoc :spring-data-commons-docs: https://raw.githubusercontent.com/spring-projects/spring-data-commons/master/src/main/asciidoc @@ -13,8 +14,10 @@ NOTE: Copies of this document may be made for your own use and for distribution toc::[] include::preface.adoc[] + :leveloffset: +1 include::new-features.adoc[] + :leveloffset: -1 [[introduction]] @@ -22,9 +25,13 @@ include::new-features.adoc[] :leveloffset: +1 include::introduction/introduction.adoc[] + include::introduction/why-sdr.adoc[] + include::introduction/requirements.adoc[] + include::introduction/getting-started.adoc[] + :leveloffset: -1 [[reference]] @@ -32,9 +39,13 @@ include::introduction/getting-started.adoc[] :leveloffset: +1 include::reference/introduction.adoc[] + include::reference/redis.adoc[] + include::reference/redis-cluster.adoc[] + include::reference/redis-repositories.adoc[] + :leveloffset: -1 [[appendixes]] @@ -43,6 +54,9 @@ include::reference/redis-repositories.adoc[] :numbered!: :leveloffset: +1 include::appendix/introduction.adoc[] + include::appendix/appendix-schema.adoc[] + include::appendix/appendix-command-reference.adoc[] + :leveloffset: -1 diff --git a/src/main/asciidoc/introduction/getting-started.adoc b/src/main/asciidoc/introduction/getting-started.adoc index 57945666d..72823fedd 100644 --- a/src/main/asciidoc/introduction/getting-started.adoc +++ b/src/main/asciidoc/introduction/getting-started.adoc @@ -21,7 +21,7 @@ NoSQL stores have taken the storage world by storm. It is a vast domain with a p [[get-started:first-steps:samples]] === Trying out the Samples -One can find various samples for key-value stores in the dedicated Spring Data example repo, at https://github.com/spring-projects/spring-data-keyvalue-examples[http://github.com/spring-projects/spring-data-keyvalue-examples]. For Spring Data Redis, you should pay particular attention to the `retwisj` sample, a Twitter-clone built on top of Redis that can be run locally or be deployed into the cloud. See its http://static.springsource.org/spring-data/data-keyvalue/examples/retwisj/current/[documentation], the following blog http://blog.springsource.com/2011/04/27/getting-started-redis-spring-cloud-foundry/[entry] or the http://retwisj.cloudfoundry.com/[live instance] for more information. +One can find various samples for key-value stores in the dedicated Spring Data example repo, at https://github.com/spring-projects/spring-data-keyvalue-examples[http://github.com/spring-projects/spring-data-keyvalue-examples]. For Spring Data Redis, you should pay particular attention to the `retwisj` sample, a Twitter-clone built on top of Redis that can be run locally or be deployed into the cloud. See its http://static.springsource.org/spring-data/data-keyvalue/examples/retwisj/current/[documentation], the following blog http://blog.springsource.com/2011/04/27/getting-started-redis-spring-cloud-foundry/[entry] for more information. [[get-started:help]] == Need Help? @@ -46,7 +46,7 @@ For information on the Spring Data source code repository, nightly builds, and s You can help make Spring Data best serve the needs of the Spring community by interacting with developers on Stack Overflow at either http://stackoverflow.com/questions/tagged/spring-data[spring-data] or http://stackoverflow.com/questions/tagged/spring-data-redis[spring-data-redis]. -If you encounter a bug or want to suggest an improvement (including to this documentation), please create a ticket on the Spring Data issue https://jira.springsource.org/browse/DATAREDIS[tracker]. +If you encounter a bug or want to suggest an improvement (including to this documentation), please create a ticket on the Spring Data issue https://jira.spring.io/browse/DATAREDIS[tracker]. To stay up to date with the latest news and announcements in the Spring eco system, subscribe to the Spring Community http://spring.io/[Portal]. diff --git a/src/main/asciidoc/introduction/requirements.adoc b/src/main/asciidoc/introduction/requirements.adoc index 22a6f123a..5db3a3103 100644 --- a/src/main/asciidoc/introduction/requirements.adoc +++ b/src/main/asciidoc/introduction/requirements.adoc @@ -1,6 +1,6 @@ [[requirements]] = Requirements -Spring Data Redis 1.x binaries require JDK level 6.0 and above and http://projects.spring.io/spring-framework/[Spring Framework] {springVersion} and above. +Spring Data Redis 2.x binaries require JDK level 8.0 and above and http://projects.spring.io/spring-framework/[Spring Framework] {springVersion} and above. -In terms of key-value stores, http://redis.io[Redis] 2.6.x or higher is required. Spring Data Redis is currently tested against the latest 3.2 release. +In terms of key-value stores, http://redis.io[Redis] 2.6.x or higher is required. Spring Data Redis is currently tested against the latest 4.0 release. diff --git a/src/main/asciidoc/reference/redis-cluster.adoc b/src/main/asciidoc/reference/redis-cluster.adoc index 0c7a065e9..17c0c5f96 100644 --- a/src/main/asciidoc/reference/redis-cluster.adoc +++ b/src/main/asciidoc/reference/redis-cluster.adoc @@ -133,9 +133,9 @@ redis-cli@127.0.0.1:7379 > cluster nodes ---- RedisClusterConnection connection = connectionFactory.getClusterConnnection(); -connection.set("thing1", value); // slot: 12182 -connection.set("{thing1}.thing2", value); // slot: 12182 -connection.set("thing2", value); // slot: 5461 +connection.set("thing1", value); // slot: 12182 +connection.set("{thing1}.thing2", value); // slot: 12182 +connection.set("thing2", value); // slot: 5461 connection.mGet("thing1", "{thing1}.thing2"); <2> @@ -150,7 +150,7 @@ connection.mGet("thing1", "thing2"); < TIP: The preceding examples demonstrate the general strategy followed by Spring Data Redis. Be aware that some operations might require loading huge amounts of data into memory to compute the desired command. Additionally, not all cross-slot requests can safely be ported to multiple single slot requests and error if misused (for example, `PFCOUNT`). -== Working with RedisTemplate and ClusterOperations +== Working with `RedisTemplate` and `ClusterOperations` See the <> section for information about the general purpose, configuration, and usage of `RedisTemplate`. diff --git a/src/main/asciidoc/reference/redis-messaging.adoc b/src/main/asciidoc/reference/redis-messaging.adoc index e1e3e9475..3936894b1 100644 --- a/src/main/asciidoc/reference/redis-messaging.adoc +++ b/src/main/asciidoc/reference/redis-messaging.adoc @@ -1,5 +1,5 @@ [[pubsub]] -= Redis Messaging and Pub/Sub += Redis Messaging (Pub/Sub) Spring Data provides dedicated messaging integration for Redis, similar in functionality and naming to the JMS integration in Spring Framework. @@ -13,7 +13,7 @@ This is an example of the pattern often called Publish/Subscribe (Pub/Sub for sh The `org.springframework.data.redis.connection` and `org.springframework.data.redis.listener` packages provide the core functionality for Redis messaging. [[redis:pubsub:publish]] -== Publishing or Sending Messages +== Publishing (Sending Messages) To publish a message, you can use, as with the other operations, either the low-level `RedisConnection` or the high-level `RedisTemplate`. Both entities offer the `publish` method, which accepts the message and the destination channel as arguments. While `RedisConnection` requires raw data (array of bytes), the `RedisTemplate` lets arbitrary objects be passed in as messages, as shown in the following example: @@ -28,7 +28,7 @@ template.convertAndSend("hello!", "world"); ---- [[redis:pubsub:subscribe]] -== Subscribing to or Receiving Messages +== Subscribing (Receiving Messages) On the receiving side, one can subscribe to one or multiple channels either by naming them directly or by using pattern matching. The latter approach is quite useful, as it not only lets multiple subscriptions be created with one command but can also listen on channels not yet created at subscription time (as long as they match the pattern). @@ -49,8 +49,8 @@ Due to its blocking nature, low-level subscription is not attractive, as it requ Furthermore, to minimize the application footprint, `RedisMessageListenerContainer` lets one connection and one thread be shared by multiple listeners even though they do not share a subscription. Thus, no matter how many listeners or channels an application tracks, the runtime cost remains the same throughout its lifetime. Moreover, the container allows runtime configuration changes so that you can add or remove listeners while an application is running without the need for a restart. Additionally, the container uses a lazy subscription approach, using a `RedisConnection` only when needed. If all the listeners are unsubscribed, cleanup is automatically performed, and the thread is released. -To help with the asynchronous nature of messages, the container requires a `java.util.concurrent.Executor` ( or Spring's `TaskExecutor`) for dispatching the messages. Depending on the load, the number of listeners, or the runtime environment, you should change or tweak the executor to better serve your needs. In particular, in managed environments (such as app servers), it is highly recommended to pick a proper `TaskExecutor` to take advantage of its runtime. -// TODO How can one know which is "proper"? +To help with the asynchronous nature of messages, the container requires a `java.util.concurrent.Executor` (or Spring's `TaskExecutor`) for dispatching the messages. Depending on the load, the number of listeners, or the runtime environment, you should change or tweak the executor to better serve your needs. In particular, in managed environments (such as app servers), it is highly recommended to pick a proper `TaskExecutor` to take advantage of its runtime. + [[redis:pubsub:subscribe:adapter]] === The MessageListenerAdapter diff --git a/src/main/asciidoc/reference/redis-repositories.adoc b/src/main/asciidoc/reference/redis-repositories.adoc index 6173e1540..3065a70dd 100644 --- a/src/main/asciidoc/reference/redis-repositories.adoc +++ b/src/main/asciidoc/reference/redis-repositories.adoc @@ -14,7 +14,7 @@ Spring Data Redis lets you easily implement domain entities, as shown in the fol ==== [source,java] ---- -@RedisHash("persons") +@RedisHash("people") public class Person { @Id String id; @@ -88,15 +88,15 @@ public void basicCrudOperations() { repo.delete(rand); <4> } ---- -<1> Generates a new `id` if the current value is `null` or reuses an already set `id` value and stores properties of type `Person` inside the Redis Hash with a key that has a pattern of `keyspace:id` -- in this case, it might be `persons:5d67b7e1-8640-4475-beeb-c666fab4c0e5`. +<1> Generates a new `id` if the current value is `null` or reuses an already set `id` value and stores properties of type `Person` inside the Redis Hash with a key that has a pattern of `keyspace:id` -- in this case, it might be `people:5d67b7e1-8640-4475-beeb-c666fab4c0e5`. <2> Uses the provided `id` to retrieve the object stored at `keyspace:id`. -<3> Counts the total number of entities available within the keyspace, `persons`, defined by `@RedisHash` on `Person`. +<3> Counts the total number of entities available within the keyspace, `people`, defined by `@RedisHash` on `Person`. <4> Removes the key for the given object from Redis. ==== [[redis.repositories.mapping]] == Object-to-Hash Mapping -The Redis Repository support persists Objects in Hashes. This requires an Object-to-Hash conversion which is done by a `RedisConverter`. The default implementation uses `Converter` for mapping property values to and from Redis native `byte[]`. +The Redis Repository support persists Objects to Hashes. This requires an Object-to-Hash conversion which is done by a `RedisConverter`. The default implementation uses `Converter` for mapping property values to and from Redis native `byte[]`. Given the `Person` type from the previous sections, the default mapping looks like the following: @@ -338,7 +338,7 @@ public class ApplicationConfig { @Override protected Iterable initialConfiguration() { - return Collections.singleton(new KeyspaceSettings(Person.class, "persons")); + return Collections.singleton(new KeyspaceSettings(Person.class, "people")); } } } @@ -368,7 +368,7 @@ public class ApplicationConfig { @Override protected Iterable initialConfiguration() { - return Collections.singleton(new KeyspaceSettings(Person.class, "persons")); + return Collections.singleton(new KeyspaceSettings(Person.class, "people")); } } } @@ -388,7 +388,7 @@ Given the sample `Person` entity shown earlier, we can create an index for `firs ==== [source,java] ---- -@RedisHash("persons") +@RedisHash("people") public class Person { @Id String id; @@ -404,8 +404,8 @@ Indexes are built up for actual property values. Saving two Persons (for example ==== [source,text] ---- -SADD persons:firstname:rand e2c7dcee-b8cd-4424-883e-736ce564363e -SADD persons:firstname:aviendha a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56 +SADD people:firstname:rand e2c7dcee-b8cd-4424-883e-736ce564363e +SADD people:firstname:aviendha a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56 ---- ==== @@ -414,7 +414,7 @@ It is also possible to have indexes on nested elements. Assume `Address` has a ` ==== [source,text] ---- -SADD persons:address.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e +SADD people:address.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e ---- ==== @@ -423,7 +423,7 @@ Furthermore, the programmatic setup lets you define indexes on map keys and list ==== [source,java] ---- -@RedisHash("persons") +@RedisHash("people") public class Person { // ... other properties omitted @@ -433,9 +433,9 @@ public class Person { List
addresses; <3> } ---- -<1> `SADD persons:attributes.map-key:map-value e2c7dcee-b8cd-4424-883e-736ce564363e` -<2> `SADD persons:relatives.map-key.firstname:tam e2c7dcee-b8cd-4424-883e-736ce564363e` -<3> `SADD persons:addresses.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e` +<1> `SADD people:attributes.map-key:map-value e2c7dcee-b8cd-4424-883e-736ce564363e` +<2> `SADD people:relatives.map-key.firstname:tam e2c7dcee-b8cd-4424-883e-736ce564363e` +<3> `SADD people:addresses.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e` ==== CAUTION: Indexes cannot be resolved on <>. @@ -456,7 +456,7 @@ public class ApplicationConfig { @Override protected Iterable initialConfiguration() { - return Collections.singleton(new SimpleIndexDefinition("persons", "firstname")); + return Collections.singleton(new SimpleIndexDefinition("people", "firstname")); } } } @@ -486,7 +486,7 @@ public class ApplicationConfig { @Override protected Iterable initialConfiguration() { - return Collections.singleton(new SimpleIndexDefinition("persons", "firstname")); + return Collections.singleton(new SimpleIndexDefinition("people", "firstname")); } } } @@ -501,7 +501,7 @@ Assume the `Address` type contains a `location` property of type `Point` that ho ==== [source,java] ---- -@RedisHash("persons") +@RedisHash("people") public class Person { Address address; @@ -529,10 +529,10 @@ repository.save(rand); <3 repository.findByAddressLocationNear(new Point(15D, 37D), new Distance(200)); <4> ---- -<1> Query method declaration on a nested property, using Point and Distance. -<2> Query method declaration on a nested property, using Circle to search within. -<3> `GEOADD persons:address:location 13.361389 38.115556 e2c7dcee-b8cd-4424-883e-736ce564363e` -<4> `GEORADIUS persons:address:location 15.0 37.0 200.0 km` +<1> Query method declaration on a nested property, using `Point` and `Distance`. +<2> Query method declaration on a nested property, using `Circle` to search within. +<3> `GEOADD people:address:location 13.361389 38.115556 e2c7dcee-b8cd-4424-883e-736ce564363e` +<4> `GEORADIUS people:address:location 15.0 37.0 200.0 km` ==== In the preceding example the, longitude and latitude values are stored by using `GEOADD` that use the object's `id` as the member's name. The finder methods allow usage of `Circle` or `Point, Distance` combinations for querying those values. @@ -584,7 +584,7 @@ The `RedisKeyExpiredEvent` holds a copy of the expired domain object as well as NOTE: Delaying or disabling the expiry event listener startup impacts `RedisKeyExpiredEvent` publishing. A disabled event listener does not publish expiry events. A delayed startup can cause loss of events because of the delayed listener initialization. -NOTE: The keyspace notification message listener alters `notify-keyspace-events` settings in Redis, if those are not already set. Existing settings are not overridden, so you must set up those settings correctly (or leav them empty). Note that `CONFIG` is disabled on AWS ElastiCache, and enabling the listener leads to an error. +NOTE: The keyspace notification message listener alters `notify-keyspace-events` settings in Redis, if those are not already set. Existing settings are not overridden, so you must set up those settings correctly (or leave them empty). Note that `CONFIG` is disabled on AWS ElastiCache, and enabling the listener leads to an error. NOTE: Redis Pub/Sub messages are not persistent. If a key expires while the application is down, the expiry event is not processed, which may lead to secondary indexes containing references to the expired object. @@ -601,7 +601,7 @@ _class = org.example.Person id = e2c7dcee-b8cd-4424-883e-736ce564363e firstname = rand lastname = al’thor -mother = persons:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56 <1> +mother = people:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56 <1> ---- <1> Reference stores the whole key (`keyspace:id`) of the referenced object. ==== @@ -709,9 +709,9 @@ The following table shows the details of data on a cluster (based on previous ex [options = "header, autowidth"] |=============== |Key|Type|Slot|Node -|persons:e2c7dcee-b8cd-4424-883e-736ce564363e|id for hash|15171|127.0.0.1:7381 -|persons:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56|id for hash|7373|127.0.0.1:7380 -|persons:firstname:rand|index|1700|127.0.0.1:7379 +|people:e2c7dcee-b8cd-4424-883e-736ce564363e|id for hash|15171|127.0.0.1:7381 +|people:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56|id for hash|7373|127.0.0.1:7380 +|people:firstname:rand|index|1700|127.0.0.1:7379 | |=============== ==== @@ -721,14 +721,14 @@ Some commands (such as `SINTER` and `SUNION`) can only be processed on the serve [options = "header, autowidth"] |=============== |Key|Type|Slot|Node -|{persons}:e2c7dcee-b8cd-4424-883e-736ce564363e|id for hash|2399|127.0.0.1:7379 -|{persons}:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56|id for hash|2399|127.0.0.1:7379 -|{persons}:firstname:rand|index|2399|127.0.0.1:7379 +|{people}:e2c7dcee-b8cd-4424-883e-736ce564363e|id for hash|2399|127.0.0.1:7379 +|{people}:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56|id for hash|2399|127.0.0.1:7379 +|{people}:firstname:rand|index|2399|127.0.0.1:7379 | |=============== ==== -TIP: Define and pin keyspaces by using `@RedisHash("{yourkeyspace}") to specific slots when you use Redis cluster. +TIP: Define and pin keyspaces by using `@RedisHash("{yourkeyspace}")` to specific slots when you use Redis cluster. [[redis.repositories.cdi-integration]] == CDI Integration diff --git a/src/main/asciidoc/reference/redis.adoc b/src/main/asciidoc/reference/redis.adoc index 02ece892f..ab01cd7b9 100644 --- a/src/main/asciidoc/reference/redis.adoc +++ b/src/main/asciidoc/reference/redis.adoc @@ -12,7 +12,7 @@ Spring Data Redis provides easy configuration and access to Redis from Spring ap [[redis:requirements]] == Redis Requirements -Spring Redis requires Redis 2.6 or above and Java SE 6.0 or above . In terms of language bindings (or connectors), Spring Redis integrates with http://github.com/xetorthio/jedis[Jedis], http://github.com/alphazero/jredis[JRedis] (Deprecated since 1.7), http://github.com/spullara/redis-protocol[SRP] (Deprecated since 1.7) and http://github.com/wg/lettuce[Lettuce], four popular open-source Java libraries for Redis. If you are aware of any other connector that we should be integrating with please send us feedback. +Spring Data Redis requires Redis 2.6 or above and Java SE 6.0 or above . In terms of language bindings (or connectors), Spring Redis integrates with http://github.com/xetorthio/jedis[Jedis], http://github.com/alphazero/jredis[JRedis] (Deprecated since 1.7), http://github.com/spullara/redis-protocol[SRP] (Deprecated since 1.7) and http://github.com/wg/lettuce[Lettuce], four popular open-source Java libraries for Redis. If you are aware of any other connector that we should be integrating with please send us feedback. [[redis:architecture]] == Redis Support High-level View @@ -39,43 +39,6 @@ The easiest way to work with a `RedisConnectionFactory` is to configure the appr IMPORTANT: Unfortunately, currently, not all connectors support all Redis features. When invoking a method on the Connection API that is unsupported by the underlying library, an `UnsupportedOperationException` is thrown. -[[redis:connectors:lettuce]] -=== Configuring the Lettuce Connector - -https://github.com/lettuce-io/lettuce-core[Lettuce] is a http://netty.io/[Netty]-based open-source connector supported by Spring Data Redis through the `org.springframework.data.redis.connection.lettuce` package. The following example shows how to create a new Lettuce connection factory: - -[source,java] ----- -@Configuration -class AppConfig { - - @Bean - public LettuceConnectionFactory redisConnectionFactory() { - - return new LettuceConnectionFactory(new RedisStandaloneConfiguration("server", 6379)); - } -} ----- - -There are also a few Lettuce-specific connection parameters that can be tweaked. By default, all `LettuceConnection` instances created by the `LettuceConnectionFactory` share the same thread-safe native connection for all non-blocking and non-transactional operations. To use a dedicated connection each time, set `shareNativeConnection` to `false`. `LettuceConnectionFactory` can also be configured to use a `LettucePool` for pooling blocking and transactional connections or all connections if `shareNativeConnection` is set to `false`. - -Lettuce integrates with Netty's http://netty.io/wiki/native-transports.html[native transports], letting you use Unix domain sockets to communicate with Redis. Make sure to include the appropriate native transport dependencies that match your runtime environment. The following example shows how to create a Lettuce Connection factory for a Unix domain socket at `/var/run/redis.sock`: - -[source,java] ----- -@Configuration -class AppConfig { - - @Bean - public LettuceConnectionFactory redisConnectionFactory() { - - return new LettuceConnectionFactory(new RedisSocketConfiguration("/var/run/redis.sock")); - } -} ----- - -NOTE: Netty currently supports the epoll (Linux) and kqueue (BSD/macOS) interfaces for OS-native transport. - [[redis:connectors:jedis]] === Configuring the Jedis Connector @@ -584,7 +547,7 @@ The atomic counters make it easy to wrap Redis key incrementation while the coll ---- -The following example shows a Java configuration example for a deque: +The following example shows a Java configuration example for a `Deque`: [source,java] ----