使用 Spring 数据在 Redis 中查询嵌套对象



我有一个 java 对象,如下所示,我存储在 redis 存储中。

@RedisHash("UserProfile")
public class UserProfile implements Serializable {
@Id String id;
@Reference PersonalInfo personalInfo = new PersonalInfo();
@Reference BusinessInfo businessInfo = new BusinessInfo();
...
}

现在,PersonalInfo对象的结构为:

public class PersonalInfo {
private String firstName;
private String lastName;
@Indexed private String userId;
private ContactInfo contactInfo = new ContactInfo();
}

请注意,PersonalInfo对象中的 userId 已编制索引。

我的目标是使用 spring 数据通过 redis 中的 userId 查询 redis 中的UserProfile对象。

CrudRepository接口将无法直接执行findByUserId(),除非我在用户配置文件对象中有userId。 我不想直接在 UserProfile 对象中使用 userId,如果有更好的方法来编写查询以按 userid 查找用户。

关于我如何做到这一点的任何建议?

更新: 我将方法如下添加到存储库中:

public interface UserProfileRepository extends CrudRepository<UserProfile, String> {
List<UserProfile> findByPersonalInfo_UserId(String userId);
}

但是在代码中调用此方法时,我收到以下错误。不确定我正在使用的 redis/spring 库是否存在问题。 我正在使用

  • 春季启动启动器父版本:1.5.2.发布
  • 春季数据版本:1.8.6.发布

例外:

java.lang.NoSuchMethodError: org.springframework.data.keyvalue.core.query.KeyValueQuery.getCriteria()Ljava/lang/Object;
at org.springframework.data.redis.repository.query.RedisQueryCreator.complete(RedisQueryCreator.java:101) ~[spring-data-redis-1.8.6.RELEASE.jar:na]
at org.springframework.data.redis.repository.query.RedisQueryCreator.complete(RedisQueryCreator.java:41) ~[spring-data-redis-1.8.6.RELEASE.jar:na]
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:88) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:73) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.createQuery(KeyValuePartTreeQuery.java:184) ~[spring-data-keyvalue-1.2.1.RELEASE.jar:na]
at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.prepareQuery(KeyValuePartTreeQuery.java:128) ~[spring-data-keyvalue-1.2.1.RELEASE.jar:na]
at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.execute(KeyValuePartTreeQuery.java:87) ~[spring-data-keyvalue-1.2.1.RELEASE.jar:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at com.sun.proxy.$Proxy66.findByPersonalInfo_UserId(Unknown Source) ~[na:na]

更新 2: 我能够通过将 springboot 版本更改为 1.5.6.RELEASE 来解决上述异常。

但是,现在我面临的问题是,当我按用户ID查询时,即使有匹配项,它也不会给我用户配置文件。

例如,redis-cli 显示:

KEYS *
UserProfile:d0876c1f-5684-4ee4-acbb-7a92b7fa25ae
UserProfile:3591e476-29d7-4c3c-a7e5-6272231f96e0
UserProfile:3591e476-29d7-4c3c-a7e5-6272231f96e0:idx
UserProfile:d0876c1f-5684-4ee4-acbb-7a92b7fa25ae:idx
UserProfile:51814a77-bf40-4912-b700-cfa50d1c4b25
UserProfile:personalInfo.userId:adrian.tremblay
UserProfile:66ba8276-1bb0-47a0-a54d-4c9d99b8bf80
UserProfile:66ba8276-1bb0-47a0-a54d-4c9d99b8bf80:idx
UserProfile:personalInfo.userId:anthony.turner
UserProfile:personalInfo.userId:ashleigh.hayes
UserProfile:a81356b0-27ef-4a34-92a3-629be5114f0e
UserProfile

当我做一个findAll,findById时,它会给我结果。 当我执行 findByPersonalInfo_UserId(( 并传递诸如 anthony.turner 或 ashleigh.hayes 之类的值时,什么都没有显示。 我是否以某种不正确的格式提供用户 ID?我尝试了一些不同的东西,但没有奏效。

更新 3:我还尝试删除 UserProfile 对象中的@Reference(以便 redis 对象被展平,而不是指向引用(。 但这也无济于事。

尝试命名您的方法,不带任何下划线,例如:

List<UserProfile> findByPersonalInfoUserId(String userId);

有类似的情况,它对我有用。也不需要@Reference注释。

使用spring-boot-starter-parent 2.0.3.RELEASE

我遇到了同样的情况,

基本上,如果你有一个引用,那么 Redis 在内部存储引用的 Id,它不能直接查询,因为它需要获取整个对象来匹配,是的,这是 Redis 的缺点(或任何基于哈希/非关系的数据库(。

您可能会问为什么不可能,从技术上讲,它可以完成,但它将是处理器和内存密集型操作,最终会影响性能,而 Redis 以其性能而闻名。

仅当您希望在多个对象(此处为用户信息(之间共享单个对象(此处为个人信息(时,才应使用@Reference

如果您想使用@Reference,可能的解决方法(假设UserProfile的"id"不等于PersonalInfo的用户Id(:

我在这个答案结束时的个人解决方案:

  1. (不推荐 - 性能缓慢( - 首先findAllUserProfile()然后遍历UserProfile中存在的每个PersonalInfo并匹配所需的字段(此处userId(

  2. (推荐( - 重组您的架构,问我为什么,因为如果您希望保留引用而不仅仅是阅读(我的意思是查询(,那么在这种情况下,非关系数据库不适合您。如果可能,重新构建以使其适合非关系结构。

注意:上述@Aurimas的解决方案很好,最适合您的情况,如果您不输入引用,那么它将创建一个新对象,该对象将存储在UserProfile对象中,但PersonalInfo的任何更改都将特定于此UserProfile,不会反映在其他UserProfile对象中。但它的优点是它可以查询:-(

因此,根据您的情况,我建议您放弃@ReferencePersonalInfo因为从逻辑上讲它不应该被共享(即个人;-((,并继续@Aurimas解决方案。

最新更新