Spring Data Redis存储库

news/2024/10/22 14:40:55/

8. Redis存储库

使用Redis存储库允许在Redis哈希中无缝地转换和存储域对象,应用自定义映射策略并利用二级索引。

Redis存储库至少需要Redis Server 2.8.0版。

8.1。用法

要访问存储在Redis中的域实体,您可以利用存储库支持,从而轻松实现这些实现。

示例5.示例人员实体
@RedisHash("persons")
public class Person {@Id String id;String firstname;String lastname;Address address;
}

我们在这里有一个非常简单的域对象。请注意,它有一个名为idannotated 的属性org.springframework.data.annotation.Id和一个@RedisHash注释类型。这两个负责创建用于保存散列的实际密钥。

注释的属性@Id以及命名id的属性被视为标识符属性。那些带有注释的人比其他人更受青睐。

现在实际上有一个负责存储和检索的组件,我们需要定义一个存储库接口。

示例6. Persist个体实体的基本知识库接口
public interface PersonRepository extends CrudRepository<Person, String> {}

随着我们的资源库的扩展,CrudRepository它提供了基本的CRUD和查找操作。我们需要将两者粘合在一起的是Spring配置。

示例7.用于Redis存储库的JavaConfig
@Configuration
@EnableRedisRepositories
public class ApplicationConfig {@Beanpublic RedisConnectionFactory connectionFactory() {return new JedisConnectionFactory();}@Beanpublic RedisTemplate<?, ?> redisTemplate() {RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();return template;}
}

鉴于上面的设置,我们可以继续并注入PersonRepository我们的组件。

示例8.访问人员实体
@Autowired PersonRepository repo;public void basicCrudOperations() {Person rand = new Person("rand", "al'thor");rand.setAddress(new Address("emond's field", "andor"));repo.save(rand);                                         repo.findOne(rand.getId());                              repo.count();                                            repo.delete(rand);                                       
}
如果当前值是null或重新使用已经设置的id值,则生成一个新的id Person,并keyspace:id在此情况下将具有模式的键存储在Redis Hash中的类型属性,例如。persons:5d67b7e1-8640-4475-beeb-c666fab4c0e5
使用提供的ID来检索存储在的对象keyspace:id
统计密钥空间内提供实体总数的定义@RedisHashPerson
从Redis中删除给定对象的键。

8.2。对象到哈希映射

Redis Repository支持持久化Hashes中的对象。这需要一个由a完成的对象哈希转换RedisConverter默认实现Converter用于将属性值映射到Redis本地和从Redis本地映射byte[]

鉴于Person前面几节中类型,默认映射如下所示:

_class = org.example.Person                 
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand                            
lastname = althor
address.city = emond's field                
address.country = andor
_class属性包含在根级别以及任何嵌套的接口或抽象类型中。
简单的属性值由路径映射。
复杂类型的属性由它们的点路径映射。
表7.默认映射规则
类型样品映射值

简单类型
(例如字符串)

String firstname =“rand”;

firstname =“rand”

复杂类型
(例如地址)

address address = new Address(“emond's field”);

address.city =“emond的字段”


简单类型列表

列表<String> nicknames = asList(“龙重生”,“lews therin”);

昵称。[0] =“龙重生”,
绰号。[1] =“lews therin”


简单类型的地图

Map <String,String> atts = asMap({“eye-color”,“gray”},{“...

atts。[eye-color] =“gray”,
atts。[hair-color] =“...


复杂类型列表

List <Address> addresses = asList(new Address(“em ...

地址。[0] .city =“emond's field”,
地址。[1] .city =“...


复杂类型的地图

Map <String,Address> addresses = asMap({“home”,new Address(“em ...

地址。[home] .city =“emond's field”,
地址。[work] .city =“...

由于平面表示结构Map键需要是简单的类型,如Strings或Numbers。

映射行为可以通过根据注册定制ConverterRedisCustomConversions这些转换器可以处理从单个转换到另一个byte[]Map<String,byte[]>而第一个转换器适用于例如。将一种复杂类型转换为例如。二进制JSON表示仍然使用默认映射哈希结构。第二个选项提供了对最终散列的完全控制。将对象写入Redis哈希将从哈希中删除内容并重新创建整个哈希,因此未映射的数据将丢失。

例9.采样字节[]转换器
@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());}@Overridepublic 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());}@Overridepublic Address convert(byte[] value) {return serializer.deserialize(value);}
}

使用上述字节[] Converter产生例如。

_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = althor
address = { city : "emond's field", country : "andor" }
示例10.示例图<String,byte []>转换器
@WritingConverter
public class AddressToMapConverter implements Converter<Address, Map<String,byte[]>> {@Overridepublic Map<String,byte[]> convert(Address source) {return singletonMap("ciudad", source.getCity().getBytes());}
}@ReadingConverter
public class MapToAddressConverter implements Converter<Address, Map<String, byte[]>> {@Overridepublic 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 = althor
ciudad = "emond's field"
自定义转换对索引分辨率没有影响。即使对于自定义转换类型,二级索引仍将被创建。

8.3。Keyspaces

密钥空间定义用于为Redis哈希创建实际密钥的前缀默认情况下,前缀设置为getClass().getName()此默认值可以通过@RedisHash聚合根级别或通过设置编程配置来更改但是,带注释的密钥空间将取代任何其他配置。

示例11.通过@EnableRedisRepositories进行Keyspace设置
@Configuration
@EnableRedisRepositories(keyspaceConfiguration = MyKeyspaceConfiguration.class)
public class ApplicationConfig {//... RedisConnectionFactory and RedisTemplate Bean definitions omittedpublic static class MyKeyspaceConfiguration extends KeyspaceConfiguration {@Overrideprotected Iterable<KeyspaceSettings> initialConfiguration() {return Collections.singleton(new KeyspaceSettings(Person.class, "persons"));}}
}
示例12.编程式Keyspace设置
@Configuration
@EnableRedisRepositories
public class ApplicationConfig {//... RedisConnectionFactory and RedisTemplate Bean definitions omitted@Beanpublic RedisMappingContext keyValueMappingContext() {return new RedisMappingContext(new MappingConfiguration(new MyKeyspaceConfiguration(), new IndexConfiguration()));}public static class MyKeyspaceConfiguration extends KeyspaceConfiguration {@Overrideprotected Iterable<KeyspaceSettings> initialConfiguration() {return Collections.singleton(new KeyspaceSettings(Person.class, "persons"));}}
}

8.4。二级索引

二级索引用于启用基于本机Redis结构的查找操作。值在每次保存时写入相应的索引,并在删除或过期时删除

8.4.1。简单的财产指数

给定示例Person实体,我们可以通过注释属性firstname创建一个索引@Indexed

示例13.注释驱动索引
@RedisHash("persons")
public class Person {@Id String id;@Indexed String firstname;String lastname;Address address;
}

索引是为实际属性值构建的。挽救两个人,例如。“rand”和“aviendha”导致设置如下所示的索引。

SADD persons:firstname:rand e2c7dcee-b8cd-4424-883e-736ce564363e
SADD persons:firstname:aviendha a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56

在嵌套元素上也可以有索引。假设Address有一个城市属性,注明@Indexed在这种情况下,一旦person.address.city不是null,我们就为每个城市设置了套数。

SADD persons:address.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e

此外,编程设置允许在地图键和列表属性上定义索引。

@RedisHash("persons")
public class Person {// ... other properties omittedMap<String,String> attributes;      Map<String Person> relatives;       List<Address> addresses;            
}
SADD persons:attributes.map-key:map-value e2c7dcee-b8cd-4424-883e-736ce564363e
SADD persons:relatives.map-key.firstname:tam e2c7dcee-b8cd-4424-883e-736ce564363e
SADD persons:addresses.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e
索引将不会在引用上解析

密钥空间相同,可以配置索引而不需要注释实际的域类型。

示例14.通过@EnableRedisRepositories设置索引
@Configuration
@EnableRedisRepositories(indexConfiguration = MyIndexConfiguration.class)
public class ApplicationConfig {//... RedisConnectionFactory and RedisTemplate Bean definitions omittedpublic static class MyIndexConfiguration extends IndexConfiguration {@Overrideprotected Iterable<IndexDefinition> initialConfiguration() {return Collections.singleton(new SimpleIndexDefinition("persons", "firstname"));}}
}
例子15.编程索引设置
@Configuration
@EnableRedisRepositories
public class ApplicationConfig {//... RedisConnectionFactory and RedisTemplate Bean definitions omitted@Beanpublic RedisMappingContext keyValueMappingContext() {return new RedisMappingContext(new MappingConfiguration(new KeyspaceConfiguration(), new MyIndexConfiguration()));}public static class MyIndexConfiguration extends IndexConfiguration {@Overrideprotected Iterable<IndexDefinition> initialConfiguration() {return Collections.singleton(new SimpleIndexDefinition("persons", "firstname"));}}
}

8.4.2。地理空间索引

假设该Address类型包含保存特定地址的地理坐标的location类型属性Point通过@GeoIndexed使用Redis GEO命令添加这些值来注释属性

@RedisHash("persons")
public class Person {Address address;// ... other properties omitted
}public class Address {@GeoIndexed Point location;// ... other properties omitted
}public interface PersonRepository extends CrudRepository<Person, String> {List<Person> findByAddressLocationNear(Point point, Distance distance);     List<Person> findByAddressLocationWithin(Circle circle);                    
}Person rand = new Person("rand", "al'thor");
rand.setAddress(new Address(new Point(13.361389D, 38.115556D)));repository.save(rand);                                                        repository.findByAddressLocationNear(new Point(15D, 37D), new Distance(200)); 
使用点和距离查询嵌套属性的方法声明。
使用Circle在内搜索嵌套属性的查询方法声明。
GEOADD persons:address:location 13.361389 38.115556 e2c7dcee-b8cd-4424-883e-736ce564363e
GEORADIUS persons:address:location 15.0 37.0 200.0 km

在上面的例子中,GEOADD使用对象id作为成员的名字来存储lon / lat值查找器方法允许查询这些值的用法CirclePoint, Distance组合。

这是不是可以组合nearwithin与其他标准。

8.5。生存时间

存储在Redis中的对象只能在一段时间内有效。这对于在Redis中保留短暂的对象尤其有用,而不必在到达其寿命时手动删除它们。以秒为单位的到期时间可以通过@RedisHash(timeToLive=…​)以及通过设置KeyspaceSettings(请参阅密钥空间)。

可以通过@TimeToLive在数字属性或方法上使用注释来设置更灵活的到期时间但是,不适用于@TimeToLive同一个类中的方法和属性。

例子16.过期
public class TimeToLiveOnProperty {@Idprivate String id;@TimeToLiveprivate Long expiration;
}public class TimeToLiveOnMethod {@Idprivate String id;@TimeToLivepublic long getTimeToLive() {return new Random().nextLong();}
}
显式注释属性将从Redis @TimeToLive回读实际TTLPTTL值。-1表示该对象没有过期关联。

存储库实现确保通过通过订阅Redis密钥空间通知RedisMessageListenerContainer

当到期被设置为正值时,EXPIRE执行相应的命令。除了保留原始文件外,幻影副本在Redis中保留并设置为在原始文件后5分钟到期。这样做是为了使存储库支持能够在密钥过期时RedisKeyExpiredEvent通过泉发布持有过期值,ApplicationEventPublisher即使原始值已经消失。所有连接的应用程序将使用Spring Data Redis存储库接收到期事件。

默认情况下,初始化应用程序时,密钥到期监听器被禁用。启动模式可以在应用程序中调整@EnableRedisRepositoriesRedisKeyValueAdapter启动监听程序,也可以在首次插入具有TTL的实体时启动。查看EnableKeyspaceEvents可能的值。

RedisKeyExpiredEvent会保存实际过期的域对象的副本以及密钥。

延迟或禁用到期事件侦听器启动会影响RedisKeyExpiredEvent发布。禁用的事件侦听器不会发布到期事件。由于延迟侦听器初始化,延迟启动可能导致事件丢失。
密钥空间通知消息侦听器将改变notify-keyspace-eventsRedis中的设置(如果这些设置尚未设置)。现有的设置不会被覆盖,所以留给用户的时候不要将它们留空。请注意,CONFIG在AWS ElastiCache中禁用了此功能,并且启用了侦听器导致的错误。
Redis Pub / Sub消息不是持久的。如果在应用程序关闭期间某个键过期,则不会处理到期事件,这可能会导致二级索引包含对已过期对象的静态引用。

8.6。坚持参考

使用标记属性@Reference允许存储简单的键引用,而不是将值复制到散列本身。在从Redis加载时,引用会自动解析并映射回对象。

示例17.示例属性参考
_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = althor
mother = persons:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56      
引用存储keyspace:id引用对象的整个键()。
引用对象在保存引用对象时不会保留更改。请确保分开保存对引用对象的更改,因为只有引用将被存储。在引用类型的属性上设置的索引不会被解析。

8.7。坚持部分更新

在某些情况下,不需要加载和重写整个实体,只需在其中设置一个新值即可。上次活动时间的会话时间戳可能是您只想更改一个属性的场景。 PartialUpdate允许在现有对象上定义setdelete操作,同时考虑更新实体本身的潜在到期时间以及索引结构。

示例18.示例部分更新
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);
将简单属性firstname设置mat
将简单属性address.city设置emond的字段,而不必传入整个对象。这在注册自定义转换时不起作用。
删除楼龄
设置复杂的地址
设置一个地图/值集合会删除先前存在的地图/集合,并用给定值替换这些值。
更改生存时间时自动更新服务器到期时间
更新复杂对象以及映射/集合结构需要与Redis进一步交互以确定现有值,这意味着可能会发现重写整个实体可能会更快。

8.8。查询和查询方法

查询方法允许从方法名称自动派生简单的查找器查询。

示例19.样本库搜索器方法
public interface PersonRepository extends CrudRepository<Person, String> {List<Person> findByFirstname(String firstname);
}
请确保在查找器方法中使用的属性设置为索引。
Redis存储库的查询方法仅支持查询具有分页的实体和实体集合。

使用派生查询方法可能并不总是足以对要执行的查询建模。RedisCallback可以更好地控制索引结构的实际匹配,甚至可以自定义添加索引结构。它只需提供一个RedisCallback返回一个或一Iterableid值的方法。

示例20.使用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.方法名称内的支持的关键字
关键词样品Redis片段

And

findByLastnameAndFirstname

SINTER …:firstname:rand …:lastname:al’thor

Or

findByLastnameOrFirstname

SUNION …:firstname:rand …:lastname:al’thor

Is,Equals

findByFirstnamefindByFirstnameIsfindByFirstnameEquals

SINTER …:firstname:rand

Top,First

findFirst10ByFirstnamefindTop5ByFirstname

 

8.9。运行在群集上的Redis存储库

在群集的Redis环境中使用Redis存储库支持很好。有关配置详细信息,请参阅Redis群集部分ConnectionFactory仍然需要考虑一些因素,因为默认的密钥分配会将实体和二级索引分散到整个集群及其插槽中。

类型插槽节点

人数:e2c7dcee-b8cd-4424-883e-736ce564363e

ID为散列

15171

127.0.0.1:7381

人数:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56

ID为散列

7373

127.0.0.1:7380

人数:姓:兰特

指数

1700

127.0.0.1:7379

当所有涉及的密钥映射到相同的插槽时,一些命令只能在服务器端处理SINTER并且SUNION只能处理。否则,计算必须在客户端完成。因此将密钥空间固定到单个插槽可以立即使用Redis服务器计算。

类型插槽节点

{}人:e2c7dcee-b8cd-4424-883e-736ce564363e

ID为散列

2399

127.0.0.1:7379

{}人:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56

ID为散列

2399

127.0.0.1:7379

{}人:姓:兰特

指数

2399

127.0.0.1:7379

在使用Redis群集时,通过`@RedisHash(“{yourkeyspace}”)定义和固定密钥空间到特定的插槽。

8.10。CDI整合

存储库接口的实例通常由一个容器创建,当使用Spring Data时,Spring是最自然的选择。有复杂的支持来轻松​​设置Spring来创建bean实例。Spring Data Redis附带一个自定义CDI扩展,允许在CDI环境中使用存储库抽象。该扩展是JAR的一部分,因此您只需要将Spring Data Redis JAR放入类路径即可。

现在,您可以设置基础结构通过实施为一个CDI生产者RedisConnectionFactoryRedisOperations

class RedisOperationsProducer {@ProducesRedisConnectionFactory 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@ApplicationScopedRedisOperations<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 {@InjectPersonRepository repository;public void businessMethod() {List<Person> people = repository.findAll();}
}

Redis存储库需要RedisKeyValueAdapterRedisKeyValueTemplate实例。如果未找到提供的bean,则这些bean由Spring Data CDI扩展创建和管理。但是,您可以提供自己的豆子配置的特定属性RedisKeyValueAdapterRedisKeyValueTemplate

源码下载:https://github.com/daqiang123/basic



http://www.ppmy.cn/news/849447.html

相关文章

安装打印时提示Inf中找不到所需的段落解决方法

HP M1216nfp 打印机在一次系统升级后无法打印。卸载打印机后&#xff0c;重新安装打印机后可以打印&#xff0c;重新启动机器后又无法打印&#xff0c;打印机为脱机状态。手动取消脱机状态后仍无法打印。经查发现&#xff0c;这台打印有个HP Smart Install Unity工具&#xff0…

IBM X System ServerGuide 8.41 服务器 系统安装 引导盘图文教程

摘要&#xff1a; IBMXSystemServerGuide8.41服务器系统安装引导盘IBMXSystemServerGuide8.41支持操作系统:32位:MicrosoftWindows2003/2003R2(Enterprise,Standard,WebandDataCenterUV)MicrosoftSmallBusinessServer2003/2003R2(Standard/PremiumEditio IBMXSystemServerGuid…

AGV小车导航控制 研一《智能控制》课程文献阅读作业

摘要 AGV&#xff08;即自动导向小车&#xff09;是一种集控制、定位、各种传感器技术于一体的设备。随着智能车技术的不断发展&#xff0c;智能车的应用范围和功能都将大为拓展&#xff0c;现已逐渐用于工业与民用领域。但是由于负载变化、使用环境条件恶劣等原因&#xff0c…

Win7下过盛*大Hack*Shield的部分驱动保护

在Win7下很多XP的驱动都不适用了&#xff01;前几个月研究了一下盛*大游戏的泡泡*堂的Hack*Shield驱动保护发现Hook了十多个内核函数&#xff0c;Ring 3和 Ring 0的双重保护&#xff0c;同时加了Themida的壳。 现在暂时发现钩住了以下函数&#xff1a; hook NtReadVirtualMemo…

采样频率和带宽的关系_ADI公司AD7380系列SAR ADC的片内过采样 - 模拟技术

作者:ADI公司JonathanColao 简介 本应用笔记讨论逐次逼近寄存器(SAR)型模数转换器(ADC)中的片内过采样。常见过采样技术有两种:正常平均和滚动平均。这些技术是在AD7380/AD7381及其高吞吐速率SARADC系列中执行的,因此平均转换数据可以直接获得,数字控制器的负担得以减轻,这…

采样频率和带宽的关系_ADI公司AD7380系列SAR ADC的片内过采样

原标题:ADI公司AD7380系列SAR ADC的片内过采样 本文引用地址: 简介 本应用笔记讨论逐次逼近寄存器(SAR)型模数转换器(ADC)中的片内过采样。常见过采样技术有两种:正常平均和滚动平均。这些技术是在AD7380/AD7381及其高吞吐速率SAR ADC系列中执行的,因此平均转换数据可以直接…

数据驱动的微动疲劳寿命预测

背景介绍 工业界中的绝大多数金属零部件在服役期间的失效都来源于循环载荷作用下的疲劳破坏&#xff0c;然而相对于常规疲劳&#xff0c;微动疲劳容易被忽视却又难以避免&#xff0c;因此对工业零部件的使用寿命危害极大&#xff0c;通常被称为“工业的癌症”。微动疲劳是指在外…

apache doris数据库集群搭建(二)

1. 概述 该文档主要介绍了主要基于apache doris数据库搭建&#xff08;一&#xff09;的基础上进行集群搭建、升级、扩容操作讲解编写。 2.软硬件需求 Doris 作为一款开源的 MPP 架构 OLAP 数据库&#xff0c;能够运行在绝大多数主流的商用服务器上。为了能够充分运用 MPP 架…