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

时间:2017-07-31 14:56:16

标签: java redis spring-data spring-data-jpa spring-data-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数据通过userIds查询redis中的UserProfile个对象。

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

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

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

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

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

  • springboot-starter-parent version:1.5.2.RELEASE
  • spring-data-redis版本:1.8.6.RELEASE

例外:

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来修复上述异常。

然而,现在我面临的问题是,当我通过userid查询时,它并没有给我UserProfiles,即使有匹配。

例如,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之类的值时,什么都没有显示出来。我是否以不正确的格式提供userId?我尝试了一些不同的东西,但没有用。

更新3:我还尝试删除UserProfile对象中的@Reference(以便redis对象变平,而不是指向引用)。但这也没有帮助。

3 个答案:

答案 0 :(得分:0)

尝试命名您的方法,不要使用任何下划线:

List<UserProfile> findByPersonalInfoUserId(String userId);

有类似的案例,对我有用。也不需要@Reference注释。

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

答案 1 :(得分:0)

我遇到了同样的情况,

基本上,如果您有一个引用,则Redis会在内部存储该引用的ID,由于需要获取整个对象以进行匹配,因此无法直接查询该ID,这是Redis(或任何基于哈希/非关系数据库的缺点) )。

您可能会问为什么不可能做到这一点,从技术上讲,它是可以做到的,但是它将占用大量处理器和内存,最终会影响性能,而Redis以其性能着称。

@Reference仅应使用,并且仅当您希望在多个对象(此处为UserInfo)中共享一个对象(此处为PersonalInfo)时使用。

可能的解决方案,如果您想使用 @Reference (假设UserProfile的'id'不等于PersonalInfo的userId): 我在此答案结尾处的个人解决方案:

  1. (不推荐-性能低下)-首先findAllUserProfile()然后遍历UserProfile中存在的每个PersonalInfo并匹配所需的字段(此处为userId)
  2. (推荐)-重组架构,问我为什么,因为如果您希望保留引用不只是阅读(我也想查询),那么在这种情况下非关系数据库不适合您。尽可能进行重组以使其适合非关系结构。

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

因此,根据您的情况,我建议您放弃@Reference for PersonalInfo,因为从逻辑上讲,不应共享它(即Personal ;-)),然后继续使用@Aurimas解决方案。

答案 2 :(得分:-1)

自定义查询目前不支持@Reference序列化和反序列化。

自定义查询的where子句中不允许使用@Reference注释标记的字段。

来源:

https://github.com/3pillarlabs/spring-data-simpledb#reference