參考文檔: https://docs.spring.io/spring-data/redis/docs/2.0.3.RELEASE/reference/html/
Redis中文教程: http://www.redis.net.cn/tutorial/3501.html
Redis官方中文文檔之Redis集群教程: http://ifeve.com/redis-cluster-tutorial/
本文是從5.3.1. RedisConnection and RedisConnectionFactory 開始翻譯的,因為前面的章節不太實用。
點擊下面的鏈接可直達官網:
-
- 5. Redis support
- 5.1. Redis Requirements
- 5.2. Redis Support High Level View
- 5.3. Connecting to Redis
- 5.4. Redis Sentinel Support
- 5.5. Working with Objects through RedisTemplate
- 5.6. String-focused convenience classes
- 5.7. Serializers
- 5.8. Hash mapping
- 5.9. Redis Messaging/PubSub
- 5.10. Redis Transactions
- 5.11. Pipelining
- 5.12. Redis Scripting
- 5.13. Support Classes
- 6. Reactive Redis support
- 7. Redis Cluster
- 8. Redis Repositories
- 5. Redis support
- Appendixes
5.3.1. RedisConnection and RedisConnectionFactory
RedisConnectionFactory: 用於創建RedisConnection 實例,根據底層配置,RedisConnectionFactory 可以返回一個新連接或現有連接(以防止連接池或共享的本地連接已經使用),使用RedisConnectionFactory的最簡單方法是通過IoC容器配置適當的連接器(連接器:connector;Jekis就是其中一種連接器),並將其注入到使用的類中。不幸的是,目前並非所有連接器都支持所有Redis功能。當調用連接的方法是底層API庫不受支持的方法時,一個UnsupportedOperationException將會被拋出。 隨着各種連接器的成熟,這種情況在未來可能會得到解決。
5.3.2. Configuring Jedis connector
Jedis是Spring Data Redis模塊通過org.springframework.data.redis.connection.jedis包支持的連接器之一。 最簡單形式的Jedis配置如下所示:
但是,對於生產環境(Production)用途,可能需要調整主機或密碼等設置:p:host-name="server" p:port="6379"
5.3.3. Configuring Lettuce connector
Lettuce是一個Spring Data Redis通過org.springframework.data.redis.connection.lettuce包支持的基於netty的可伸縮線程安全的開源連接器(Redis客戶端)。多個線程可以共享同一個RedisConnection。它利用優秀netty NIO框架來高效地管理多個連接。Lettuce 的詳細介紹和下載地址:點擊下載
配置方式與Jedis類似:
還有一些可以調整的Lettuce專用的連接參數。 默認情況下,由LettuceConnectionFactory創建的所有LettuceConnection共享用於所有非阻塞和非事務操作的相同線程安全本機連接。 將shareNativeConnection設置為false,以便每次都使用專用連接。 LettuceConnectionFactory也可以配置為使用LettucePool來共享阻塞和事務連接,或者如果shareNativeConnection設置為false,則可以使用所有連接。
5.4. Redis Sentinel Support
為了處理高可用性的Redis,RedisSentinel使用RedisSentinelConfiguration支持Redis Sentinel
/** * jedis */ @Bean public RedisConnectionFactory jedisConnectionFactory() { RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster") .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380); return new JedisConnectionFactory(sentinelConfig); } /** * Lettuce */ @Bean public RedisConnectionFactory lettuceConnectionFactory() { RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster") .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380); return new LettuceConnectionFactory(sentinelConfig); }RedisSentinelConfiguration也可以通過PropertySource(在applicatoin.properties或者其他在classpath上的properties)定義。
配置屬性
spring.redis.sentinel.master:主節點(master node)的名稱。
spring.redis.sentinel.nodes:逗號分隔的主機:端口對列表(host:port pairs)。
以下是一個使用Lua腳本執行常見“檢查並設置”場景的示例。對於Redis腳本來說,這是一個理想的用例,因為它要求我們以原子方式執行一組命令,並且一個命令的行為受另一個命令的影響。
@Bean public RedisScript<Boolean> script() { ScriptSource scriptSource = new ResourceScriptSource(new ClassPathResource("META-INF/scripts/checkandset.lua"); return RedisScript.of(scriptSource, Boolean.class); }
public class Example { @Autowired RedisScript<Boolean> script; public boolean checkAndSet(String expectedValue, String newValue) { return redisTemplate.execute(script, singletonList("key"), asList(expectedValue, newValue)); } }
-- checkandset.lua local current = redis.call('GET', KEYS[1]) if current == ARGV[1] then redis.call('SET', KEYS[1], ARGV[2]) return true end return false上面的代碼配置RedisScript指向名為checkandset.lua的文件,該文件預計會返回一個布爾值。腳本resultType應該是Long,Boolean,List或反序列化值類型之一。 如果腳本返回丟棄狀態(即“OK”),它也可以為空。 在應用程序上下文中配置DefaultRedisScript的單個實例是非常理想的,以避免在每次腳本執行時重新計算腳本的SHA1。
上面的checkAndSet方法執行腳本可以作為事務或管道的一部分在SessionCallback中執行。 有關更多信息,請參閱Redis事務和管道傳輸。
Spring Data Redis提供的腳本支持還允許您使用Spring Task和Scheduler抽象計划定期執行Redis腳本。 有關更多詳細信息,請參閱Spring Framework文檔。
5.13. Support Classes
Package org.springframework.data.redis.support提供各種可重用組件,這些組件依賴Redis作為后備存儲。目前,該軟件包在Redis之上包含各種基於JDK的界面實現,如原子計數器和JDK集合。
原子計數器可以輕松地包裝Redis密鑰增量,而集合允許以最小的存儲空間或API泄漏輕松管理Redis密鑰:特別是RedisSet和RedisZSet接口可以輕松訪問Redis支持的集合操作,例如交集intersection
和聯合union
,而RedisList在Redis之上實現了List,Queue和Deque契約(及其等效的同級同胞),將存儲作為FIFO(先進先出),LIFO(后進先出)或采用最小配置的集合:
public class AnotherExample { // injected private Deque<String> queue; public void addTag(String tag) { queue.push(tag); } }
如上例所示,使用代碼與實際的存儲實現分離 - 事實上,沒有指出在下面使用Redis的情況。 這使得從開發到生產環境變得透明並且極大地提高了可測試性(Redis實現可以被在內存中的一個所取代)。
5.13.1. Support for Spring Cache Abstraction - 2.0中的改變
@Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { return RedisCacheManager.create(connectionFactory); }
RedisCacheManager行為可以通過RedisCacheManagerBuilder配置,允許設置默認的RedisCacheConfiguration,事務行為和預定義的緩存。
RedisCacheManager cm = RedisCacheManager.builder(connectionFactory) .cacheDefaults(defaultCacheConfig()) .initialCacheConfigurations(singletonMap("predefined", defaultCacheConfig().disableCachingNullValues())) .transactionAware() .build();
通過RedisCacheManager創建的RedisCache的行為通過RedisCacheConfiguration定義。該配置允許設置密鑰到期時間,前綴和RedisSerializer以轉換為二進制存儲格式和從二進制存儲格式轉換。 如上所示,RedisCacheManager允許定義每個緩存庫上的配置。
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(1)) .disableCachingNullValues();
RedisCacheManager默認使用無鎖 Lock-free RedisCacheWriter來讀取和寫入二進制值。無鎖緩存提高了吞吐量。 缺少入口鎖定可能會導致putIfAbsent和clean方法的重疊非原子命令,因為那些方法需要將多個命令發送到Redis。 鎖定副本通過設置顯式鎖定鍵explicit lock key並檢查是否存在此鍵來防止命令重疊,這會導致額外的請求和潛在的命令等待時間。
可以選擇加入鎖定行為如下:
RedisCacheManager cm = RedisCacheManager.build(RedisCacheWriter.lockingRedisCacheWriter()) .cacheDefaults(defaultCacheConfig()) ...
Table 4. RedisCacheManager defaults
Table 5. RedisCacheConfiguration defaults
6. Reactive Redis support
本節介紹Redis支持以及如何入門。 你會發現與imperative Redis support有某些重疊。
6.1. Redis Requirements
Spring Data Redis需要Redis 2.6或更高版本以及Java SE 8.0或更高版本。 在語言綁定(或連接器)方面,Spring Data Redis目前與Lettuce集成為唯一的reactive Java連接器。 Project Reactor被作為reactive組合庫。
6.2. Connecting to Redis using a reactive driver
使用Redis和Spring的首要任務之一是通過IoC容器連接到商店。為此,需要Java連接器connector(或綁定binding)。無論選擇哪個庫,只有一組SpringDataRedis API需要使用,它們在所有連接器中的行為一致,org.springframework.data.redis.connection包和它的ReactiveRedisConnection和ReactiveRedisConnectionFactory接口,以便處理 並檢索到Redis的活動連接。
6.2.1. Redis Operation Modes
Redis可以作為獨立服務器運行,使用Redis Sentinel或Redis Cluster模式運行。 Lettuce
支持上面提到的所有連接類型。
6.2.2. ReactiveRedisConnection and ReactiveRedisConnectionFactory
ReactiveRedisConnections的實例是通過ReactiveRedisConnectionFactory創建的。另外,工廠充當PersistenceExceptionTranslators,意味着一旦聲明,它允許人們處理成明確的異常。例如,通過使用@Repository注釋和AOP進行異常處理。 有關更多信息,請參閱Spring Framework文檔中的專用章節 section 。
根據底層配置,工廠可以返回新連接或現有連接(如果使用池或共享本地連接)。
使用Reactive RedisConnectionFactory的最簡單方法是通過IoC容器配置適當的連接器,並將其注入到使用的類中。
6.2.3. Configuring Lettuce connector
為Lettuce設置ReactiveRedisConnectionFactory可以按如下方式完成:
@Bean public ReactiveRedisConnectionFactory connectionFactory() { return new LettuceConnectionFactory("localhost", 6379); }
使用LettuceClientConfigurationBuilder的更復雜的配置(包括SSL和超時)如下所示:
@Bean public ReactiveRedisConnectionFactory lettuceConnectionFactory() { LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .useSsl().and() .commandTimeout(Duration.ofSeconds(2)) .shutdownTimeout(Duration.ZERO) .build(); return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379), clientConfig); }
有關更詳細的客戶端配置調整,請參閱LettuceClientConfiguration。
6.3. Working with Objects through ReactiveRedisTemplate
Most users are likely to use ReactiveRedisTemplate
and its corresponding package org.springframework.data.redis.core
- the template is in fact the central class of the Redis module due to its rich feature set. The template offers a high-level abstraction for Redis interactions. While ReactiveRedisConnection
offers low level methods that accept and return binary values (ByteBuffer
), the template takes care of serialization and connection management, freeing the user from dealing with such details.
Moreover, the template provides operation views (following the grouping from Redis command reference) that offer rich, generified interfaces for working against a certain type as described below:
此外,該模板提供了操作視圖(來自Redis命令參考的分組之后),該視圖提供了豐富的,通用的接口,用於針對某種類型進行處理,如下所述:
Table 6. Operational views

配置完成后,該模板是線程安全的,可以在多個實例中重復使用。
開箱即用,ReactiveRedisTemplate在其大部分操作中使用基於Java的序列化程序。 這意味着模板寫入或讀取的任何對象都將通過RedisElementWriter和RedisElementReader進行序列化/反序列化。序列化上下文在構建時傳遞給模板,Redis模塊在org.springframework.data.redis.serializer包中提供了幾個可用實現 - 請參閱序列化程序以獲取更多信息。
@Configuration class RedisConfiguration { @Bean ReactiveRedisTemplate<String, String> reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) { return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string()); } }
public class Example { @Autowired private ReactiveRedisTemplate<String, String> template; public Mono<Long> addLink(String userId, URL url) { return template.opsForList().leftPush(userId, url.toExternalForm()); } }
6.4. Reactive Scripting
通過ReactiveRedisTemplate使用ReactiveScriptExecutor也可以實現Reactive基礎構建執行 Redis scripts的功能。
public class Example { @Autowired private ReactiveRedisTemplate<String, String> template; public Flux<Long> theAnswerToLife() { DefaultRedisScript<Long> script = new DefaultRedisScript<>(); script.setLocation(new ClassPathResource("META-INF/scripts/42.lua")); script.setResultType(Long.class); return reactiveTemplate.execute(script); } }
7. Redis Cluster
使用Redis群集Redis Cluster需要Redis Server 3.0+版本,並提供了一套自己的特性和功能。 有關更多信息,請參閱群集教程Cluster Tutorial。
7.1. Enabling Redis Cluster
示例1. Redis群集的示例RedisConnectionFactory配置
@Component @ConfigurationProperties(prefix = "spring.redis.cluster") public class ClusterConfigurationProperties { /* * spring.redis.cluster.nodes[0] = 127.0.0.1:7379 * spring.redis.cluster.nodes[1] = 127.0.0.1:7380 * ... */ List<String> nodes; /** * Get initial collection of known cluster nodes in format {@code host:port}. * * @return */ public List<String> getNodes() { return nodes; } public void setNodes(List<String> nodes) { this.nodes = nodes; } } @Configuration public class AppConfig { /** * Type safe representation of application.properties */ @Autowired ClusterConfigurationProperties clusterProperties; public @Bean RedisConnectionFactory connectionFactory() { return new JedisConnectionFactory( new RedisClusterConfiguration(clusterProperties.getNodes())); } }
RedisClusterConfiguration
可以通過 PropertySource
定義
-
spring.redis.cluster.nodes
: 逗號分隔host:port -
spring.redis.cluster.max-redirects
: 允許cluster重定向的數量
初始配置將驅動程序庫指向初始集群節點集。 活動群集重新配置所產生的更改只會保留在本機驅動程序中,而不會寫回配置。
7.2. Working With Redis Cluster Connection
盡管重定向到相應的插槽服務節點的特定密鑰由驅動程序庫處理,但高級函數(如收集跨節點的信息)或將命令發送到群集中由RedisClusterConnection覆蓋的所有節點。從上面的例子中,我們可以看到,當獲取結果和返回的一組鍵值時,key(pattern)方法獲取集群中的每個主節點,並同時對每個主節點執行KEYS命令。僅僅請求單個節點的密鑰,RedisClusterConnection為那些(如密鑰(節點,模式))提供重載。
RedisClusterNode可以從RedisClusterConnection.clusterGetNodes獲得,也可以使用主機和端口或節點ID構建。
Example 2. Sample of Running Commands Across the Cluster
當所有密鑰映射到同一個插槽時,本地驅動程序庫會自動為跨插槽請求(如MGET)提供服務。但是,一旦情況並非如此,RedisClusterConnection將針對插槽服務節點執行多個並行GET命令,並再次返回累計結果。顯然,這比單個插槽執行的性能差,因此應該小心使用。 如有疑問,請在{my-prefix} .foo和{my-prefix} .bar這樣的大括號中提供一個前綴,將它們映射到相同的插槽編號,從而考慮將密鑰固定到同一個插槽。
Example 3. Sample of Cross Slot Request Handling
以上提供了簡單的例子來演示Spring Data Redis遵循的一般策略。 請注意,某些操作可能需要將大量數據加載到內存中才能計算所需的命令。此外,並非所有的交叉插槽請求都可以安全地移植到多個單插槽請求中,並且如果使用不當(例如PFCOUNT),則會出錯。
7.3. Working With RedisTemplate and ClusterOperations
RedisTemplate的一般用途請參閱5.5: http://blog.csdn.net/michaelehome/article/details/79485661
使用任何JSON-RedisSerializer設置RedisTemplate#keySerializer時請小心,因為更改json結構會對散列槽計算產生直接影響。
RedisTemplate可通過RedisTemplate.opsForCluster()獲取的ClusterOperations接口提供對集群特定操作的訪問。 這允許在集群內的單個節點上明確執行命令,同時保留為模板配置的解除/序列化功能,並提供管理命令,例如CLUSTER MEET或更高級別的操作。resharding。
Example 4. Accessing RedisClusterConnection via RedisTemplate
8. Redis Repositories
Redis存儲庫至少需要Redis Server 2.8.0版。
8.1. Usage
Example 5. Sample Person Entity
@RedisHash("persons") public class Person { @Id String id; String firstname; String lastname; Address address; }
我們在這里有一個非常簡單的域對象domain object。請注意,它有一個名為id的屬性,其中注明了org.springframework.data.annotation.Id和一個類型為@RedisHash的注解。這兩個負責創建用於保存散列的實際密鑰。用@Id注釋的屬性以及那些名為id的屬性被視為標識符屬性。 那些帶有注釋的比其他的更受青睞。
現在實際上有一個負責存儲storage和檢索retrieval的組件,我們需要定義一個存儲庫接口repository interface。
Example 6. Basic Repository Interface To Persist Person Entities
public interface PersonRepository extends CrudRepository<Person, String> { }
由於我們的repository 擴展了CrudRepository,它提供了基本的CRUD和查找操作。 我們需要將兩者粘合在一起的是Spring配置。
Example 7. JavaConfig for Redis Repositories
@Configuration @EnableRedisRepositories public class ApplicationConfig { @Bean public RedisConnectionFactory connectionFactory() { return new JedisConnectionFactory(); } @Bean public RedisTemplate<?, ?> redisTemplate() { RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>(); return template; } }
鑒於上面的設置,我們可以繼續並將PersonRepository注入到組件中。
Example 8. Access to Person Entities
1. 如果當前值為null,則生成一個新的ID,或重用一個id,然后設置id的值,將Key和keyspace:id,還有Person類型的屬性一起存儲到Redis Hash中。對於這種情況,例如: persons:5d67b7e1-8640-4475-BEEB-c666fab4c0e5。
2. 使用提供的ID檢索存儲在keyspace:id處的對象。
3. 通過在Person上使用@RedisHash計算keyspace persons中的所有可用實體的總數。
4. 從Redis中刪除給定對象的鍵。
8.2. Object to Hash Mapping
基於前面幾節中的Person類型,默認映射如下所示:
1. _class屬性包含在根級別以及任何嵌套的接口或抽象類型中。
2. 簡單的屬性值是通過路徑被映射的。
3. 復雜類型的屬性由它們的點路徑映射。
Table 7. Default Mapping Rules
Mapping behavior can be customized by registering the according Converter
in RedisCustomConversions
. Those converters can take care of converting from/to a single byte[]
as well as Map<String,byte[]>
whereas the first one is suitable for eg. converting one complex type to eg. a binary JSON representation that still uses the default mappings hash structure. The second option offers full control over the resulting hash. Writing objects to a Redis hash will delete the content from the hash and re-create the whole hash, so not mapped data will be lost.
映射行為可以通過在RedisCustomConversions中注冊相應的Converter來定制。這些轉換器可以處理單個字節byte[]以及Map <String,byte[]>的轉換,而第一個轉換器是合適的,例如,轉換一種復雜類型,例如,一個二進制JSON表示仍然使用默認映射哈希結構。 第二個選項提供了對返回的Hash的完全控制。將對象寫入Redis Hash將從哈希中刪除內容並重新創建整個哈希,因此未映射的數據將丟失。
Example 9. Sample byte[] Converters
@WritingConverter public class AddressToBytesConverter implements Converter<Address, byte[]> { private final Jackson2JsonRedisSerializer<Address> serializer; public AddressToBytesConverter() { serializer = new Jackson2JsonRedisSerializer<Address>(Address.class); serializer.setObjectMapper(new ObjectMapper()); } @Override public byte[] convert(Address value) { return serializer.serialize(value); } } @ReadingConverter public class BytesToAddressConverter implements Converter<byte[], Address> { private final Jackson2JsonRedisSerializer<Address> serializer; public BytesToAddressConverter() { serializer = new Jackson2JsonRedisSerializer<Address>(Address.class); serializer.setObjectMapper(new ObjectMapper()); } @Override public Address convert(byte[] value) { return serializer.deserialize(value); } }
使用上述byte[] Converter
產生的例子:
_class = org.example.Person id = e2c7dcee-b8cd-4424-883e-736ce564363e firstname = rand lastname = al’thor address = { city : "emond's field", country : "andor" }
Example 10. Sample Map<String,byte[]> Converters
@WritingConverter public class AddressToMapConverter implements Converter<Address, Map<String,byte[]>> { @Override public Map<String,byte[]> convert(Address source) { return singletonMap("ciudad", source.getCity().getBytes()); } } @ReadingConverter public class MapToAddressConverter implements Converter<Address, Map<String, byte[]>> { @Override public Address convert(Map<String,byte[]> source) { return new Address(new String(source.get("ciudad"))); } }
用上述的Map Converter
產生的例子:
_class = org.example.Person id = e2c7dcee-b8cd-4424-883e-736ce564363e firstname = rand lastname = al’thor ciudad = "emond's field"自定義轉換對索引的定義沒有任何影響。 即使對於自定義轉換類型,二級索引也將會被創建。
8.3. Keyspaces
getClass().getName()
. This default can be altered via
@RedisHash
on aggregate root level or by setting up a programmatic configuration. However, the annotated keyspace supersedes any other configuration.
Keyspaces定義了用於為Redis Hash創建實際Key的前綴。 默認情況下,前綴設置為getClass().getName()。 這個默認值可以通過在類上使用@RedisHash或通過設置程序的配置來改變。 但是,帶注解的keyspace將取代任何其他配置。
Example 11. Keyspace Setup via @EnableRedisRepositories
@Configuration @EnableRedisRepositories(keyspaceConfiguration = MyKeyspaceConfiguration.class) public class ApplicationConfig { //... RedisConnectionFactory and RedisTemplate Bean definitions omitted public static class MyKeyspaceConfiguration extends KeyspaceConfiguration { @Override protected Iterable<KeyspaceSettings> initialConfiguration() { return Collections.singleton(new KeyspaceSettings(Person.class, "persons")); } } }
Example 12. Programmatic Keyspace setup
@Configuration @EnableRedisRepositories public class ApplicationConfig { //... RedisConnectionFactory and RedisTemplate Bean definitions omitted @Bean public RedisMappingContext keyValueMappingContext() { return new RedisMappingContext( new MappingConfiguration( new MyKeyspaceConfiguration(), new IndexConfiguration())); } public static class MyKeyspaceConfiguration extends KeyspaceConfiguration { @Override protected Iterable<KeyspaceSettings> initialConfiguration() { return Collections.singleton(new KeyspaceSettings(Person.class, "persons")); } } }
8.4. Secondary Indexes
二級索引用於啟用基於本機Redis結構的查找操作。 值在每次保存時寫入相應的索引,並在對象被刪除或過期時被刪除。
8.4.1. Simple Property Index
Example 13. Annotation driven indexing
@RedisHash("persons") public class Person { @Id String id; @Indexed String firstname; String lastname; Address address; }
索引是為實際屬性值構建的。 保存兩個Persons,例如。 “rand”和“aviendha”將會設置如下的索引。
SADD persons:firstname:rand e2c7dcee-b8cd-4424-883e-736ce564363e SADD persons:firstname:aviendha a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56
在嵌套元素上也可以有索引。 假設地址具有用@Indexed注釋的城市屬性。 在那種情況下,一旦person.address.city不為空,我們就為每個城市設置了Sets。
SADD persons:address.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e
此外,編程設置允許在map keys和list屬性上定義索引。
Same as with keyspaces it is possible to configure indexes without the need of annotating the actual domain type.
與keyspaces相同,可以配置索引而不需要在實際的域類型上使用注解。
Example 14. Index Setup via @EnableRedisRepositories
@Configuration @EnableRedisRepositories(indexConfiguration = MyIndexConfiguration.class) public class ApplicationConfig { //... RedisConnectionFactory and RedisTemplate Bean definitions omitted public static class MyIndexConfiguration extends IndexConfiguration { @Override protected Iterable<IndexDefinition> initialConfiguration() { return Collections.singleton(new SimpleIndexDefinition("persons", "firstname")); } } }
Example 15. Programmatic Index setup
@Configuration @EnableRedisRepositories public class ApplicationConfig { //... RedisConnectionFactory and RedisTemplate Bean definitions omitted @Bean public RedisMappingContext keyValueMappingContext() { return new RedisMappingContext( new MappingConfiguration( new KeyspaceConfiguration(), new MyIndexConfiguration())); } public static class MyIndexConfiguration extends IndexConfiguration { @Override protected Iterable<IndexDefinition> initialConfiguration() { return Collections.singleton(new SimpleIndexDefinition("persons", "firstname")); } } }
8.4.2. Geospatial Index
Address
類型包含一個類型為Point的location屬性,該位置保存特定地址的地理坐標。 通過使用@GeoIndexed注解屬性,將使用Redis GEO命令添加這些值。
在上面的例子中,使用GEOADD和對象id作為成員的名字來存儲lon / lat值。 查找方法允許使用Circle
或 Point, Distance
組合來查詢這些值。
不能將near/within與其他標准組合在一起。
8.5. Time To Live
可以通過在numeric屬性或方法上使用@TimeToLive注釋來設置更靈活的到期時間。但是,不要在同一個類中的方法和屬性上應用@TimeToLive。
Example 16. Expirations
public class TimeToLiveOnProperty { @Id private String id; @TimeToLive private Long expiration; } public class TimeToLiveOnMethod { @Id private String id; @TimeToLive public long getTimeToLive() { return new Random().nextLong(); } }使用@TimeToLive顯式注釋屬性將從Redis回讀實際的TTL或PTTL值。 -1表示該對象沒有過期關聯。
repository的實現確保了通過RedisMessageListenerContainer訂閱Redis keyspace notifications。
當到期被設置為正值時,執行相應的EXPIRE命令。除了保留原始文件外,仿真副本被存儲在Redis中並設置為在原始文件保留5分鍾后到期。這樣做的目的在於,開啟Repository支持,通過Springs ApplicationEventPublisher發布RedisKeyExpiredEvent持有的過期值(當密鑰過期甚至原始值已經消失)。所有連接的應用程序將使用Spring Data Redis repository接收到RedisKeyExpiredEvent。
默認情況下,初始化應用程序時,key expiry listener是被禁用的。可以在@EnableRedisRepositories或RedisKeyValueAdapter中調整為啟用模式,以啟動應用程序的listener,或者在第一次插入具有TTL的實體時自動啟動listener。可用的值請參閱EnableKeyspaceEvents。
RedisKeyExpiredEvent將保存實際過期的域對象以及密鑰的副本。
延遲或禁用到期事件偵聽器啟動會影響RedisKeyExpiredEvent發布。 被禁用的事件偵聽器不會發布到期事件。 由於延遲偵聽器初始化,延遲啟動可能導致事件丟失。
keyspace通知消息偵聽器將在Redis中更改notify-keyspace-events設置(如果尚未設置這些設置)。 現有的設置不會被覆蓋,所以留給用戶去正確的設置這些,當現有的設置不為空時。 請注意,在AWS ElastiCache上禁用了CONFIG,啟用監聽器將導致錯誤。
Redis Pub / Sub消息不是持久的。 如果在應用程序關閉期間某個鍵過期,則不會處理到期事件,這可能會導致secondary indexes引用已過期的對象。
8.6. Persisting References
使用@Reference標記屬性允許存儲簡單的鍵引用,而不是將值復制到Hash本身。 在從Redis加載時,引用會自動解析並映射回對象。
Example 17. Sample Property Reference
_class = org.example.Person id = e2c7dcee-b8cd-4424-883e-736ce564363e firstname = rand lastname = al’thor mother = persons:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56 (1)(1)這個引用存儲了被引用對象的整個鍵(keyspace:id)。
在保存引用對象時,引用對象不會保留更改。 請確保分開保存對引用對象的更改,因為只有引用將被存儲。 在引用類型的屬性上設置的索引不會被解析。
8.7. Persisting Partial Updates
在某些情況下,不需要加載和重寫整個實體,只需在其中設置一個新值即可。 上次活動時間的會話時間戳可能是您只想更改一個屬性的場景。 PartialUpdate允許定義對現有對象的設置和刪除操作,同時負責更新實體本身的潛在到期時間以及索引結構。
PartialUpdate<Person> update = new PartialUpdate<Person>("e2c7dcee", Person.class) .set("firstname", "mat") .set("address.city", "emond's field") .del("age"); template.update(update); update = new PartialUpdate<Person>("e2c7dcee", Person.class) .set("address", new Address("caemlyn", "andor")) .set("attributes", singletonMap("eye-color", "grey")); template.update(update); update = new PartialUpdate<Person>("e2c7dcee", Person.class) .refreshTtl(true); .set("expiration", 1000); template.update(update);
1. Set the simple property firstname to mat. 2. Set the simple property address.city to emond’s field without having to pass in the entire object. This does not work when a custom conversion is registered. 3. Remove the property age. 4. Set complex property address. 5. Set a map/collection of values removes the previously existing map/collection and replaces the values with the given ones. 6. Automatically update the server expiration time when altering Time To Live.
更新復雜對象以及映射/集合結構需要與Redis進一步交互以確定現有值,這意味着可能會發現重寫整個實體可能會更快。
8.8. Queries and Query Methods
Example 19. Sample Repository finder Method
public interface PersonRepository extends CrudRepository<Person, String> { List<Person> findByFirstname(String firstname); }請確保在查找器方法中使用的屬性設置為索引。
Redis存儲庫的查詢方法僅支持查詢具有分頁的實體和實體集合。
使用派生查詢derived query 方法可能並不總是足以對要執行的查詢建模。 RedisCallback提供了對索引結構的實際匹配或甚至自定義添加的更多控制。 它所需要的就是提供一個RedisCallback,它返回一個單獨的或一組Iterable set的id值。
Example 20. Sample finder using RedisCallback
String user = //... List<RedisSession> sessionsByUser = template.find(new RedisCallback<Set<byte[]>>() { public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException { return connection .sMembers("sessions:securityContext.authentication.principal.username:" + user); }}, RedisSession.class);
以下概述了Redis支持的關鍵字以及包含該關鍵字的方法。
8.9. Redis Repositories running on Cluster
當所有相關密鑰映射到同一個插槽時,只能在服務器端處理像SINTER和SUNION這樣的一些命令。 否則,計算必須在客戶端完成。 因此將密鑰空間keyspaces 固定到單個插槽slot,可以立即使用Redis服務器計算。
在使用Redis群集時,通過`@RedisHash(“{yourkeyspace}”)定義和固定密鑰空間到特定的插槽。
8.10. CDI integration
Instances of the repository interfaces are usually created by a container, which Spring is the most natural choice when working with Spring Data. There’s sophisticated support to easily set up Spring to create bean instances. Spring Data Redis ships with a custom CDI extension that allows using the repository abstraction in CDI environments. The extension is part of the JAR so all you need to do to activate it is dropping the Spring Data Redis JAR into your classpath.
You can now set up the infrastructure by implementing a CDI Producer for the RedisConnectionFactory
and RedisOperations
:
您現在可以通過為RedisConnectionFactory和RedisOperations實施CDI Producer來設置基礎架構:
class RedisOperationsProducer { @Produces RedisConnectionFactory redisConnectionFactory() { JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(new RedisStandaloneConfiguration()); jedisConnectionFactory.afterPropertiesSet(); return jedisConnectionFactory; } void disposeRedisConnectionFactory(@Disposes RedisConnectionFactory redisConnectionFactory) throws Exception { if (redisConnectionFactory instanceof DisposableBean) { ((DisposableBean) redisConnectionFactory).destroy(); } } @Produces @ApplicationScoped RedisOperations<byte[], byte[]> redisOperationsProducer(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>(); template.setConnectionFactory(redisConnectionFactory); template.afterPropertiesSet(); return template; } }必要的設置可能因您運行的JavaEE環境而異。
Spring Data Redis CDI擴展將挑選所有可用作CDI bean的Repositories,並在容器請求存儲庫類型的bean時創建Spring Data repository的代理。 因此,獲取Spring Data存儲庫的一個實例是聲明一個@Injected屬性的問題:
class RepositoryClient { @Inject PersonRepository repository; public void businessMethod() { List<Person> people = repository.findAll(); } }Redis存儲庫需要RedisKeyValueAdapter和RedisKeyValueTemplate實例。 如果未找到提供的bean,則這些bean由Spring Data CDI擴展創建和管理。 但是,您可以提供自己的Bean來配置RedisKeyValueAdapter和RedisKeyValueTemplate的特定屬性。