参考文档: 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的特定属性。