Spring Boot 2.1.0 和 Java 11 上的 Spring Data Redis 无法正常工作

Posted

技术标签:

【中文标题】Spring Boot 2.1.0 和 Java 11 上的 Spring Data Redis 无法正常工作【英文标题】:Spring Data Redis on Spring Boot 2.1.0 and Java 11 not working 【发布时间】:2019-04-16 22:36:39 【问题描述】:

我将我的应用程序更新为 Spring Boot 2.1.0 和 Java 11。从那时起,我的 Redis 就不再工作了。

当我调用findById() 并且结果为空时,就没有问题了。 当我调用findById() 并且有结果时,应用程序/线程此时卡住了,没有任何反应。

当我使用 Spring Boot 2.0.6 和 Java 9 时,相同的代码运行良好。

我尝试使用LettuceConnectionFactoryJedisConnectionFactory 得到相同的结果。

我的 Redis 配置:

@Configuration
@EnableRedisRepositories
public class RedisConfiguration 

    @Bean
    RedisConnectionFactory connectionFactory() 
        return new LettuceConnectionFactory();
    

    @Bean
    @Primary
    RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) 
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        return template;
    

我的实体:

@Value
@RedisHash("token")
public class Token 

    @Id 
    private String key;

    private String value;

    @TimeToLive
    private Long expiration;


我的存储库只是扩展了CrudRepository,我只使用提供的方法。

Redis-Server 版本是 Redis server v=4.0.9 在 OSX (dev) / Ubuntu (test) 上运行。

我是否错过了使用 Java 11 / Boot 2.1 必须应用的一些更改?

【问题讨论】:

你可以试试这个template.afterPropertiesSet()RedisConnectionsFactory.afterPropertiesSet()然后返回两个对象 从 spring boot 2.0.3 和 java 9 升级到 spring boot 2.1.0 和 java 11 后,我的 mongo 遇到了同样的问题。确实。您是否找到了使用 @AllArgsConstructor 以外的其他解决方案,因为我不想使用这个库。 【参考方案1】:

我找到了解决方案。我创建了一个测试项目,看到CrudRepository#findById()方法抛出了如下异常。

Caused by: org.springframework.data.keyvalue.core.UncategorizedKeyValueException: No accessor to set property @org.springframework.data.redis.core.TimeToLive(unit=SECONDS)private final java.lang.Long com.test.redisbug.Token.expiration!; nested exception is java.lang.UnsupportedOperationException: No accessor to set property @org.springframework.data.redis.core.TimeToLive(unit=SECONDS)private final java.lang.Long com.test.redisbug.Token.expiration!
    at org.springframework.data.keyvalue.core.KeyValuePersistenceExceptionTranslator.translateExceptionIfPossible(KeyValuePersistenceExceptionTranslator.java:55) ~[spring-data-keyvalue-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.keyvalue.core.KeyValueTemplate.resolveExceptionIfPossible(KeyValueTemplate.java:462) ~[spring-data-keyvalue-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.keyvalue.core.KeyValueTemplate.execute(KeyValueTemplate.java:348) ~[spring-data-keyvalue-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.keyvalue.core.KeyValueTemplate.findById(KeyValueTemplate.java:251) ~[spring-data-keyvalue-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.keyvalue.repository.support.SimpleKeyValueRepository.findById(SimpleKeyValueRepository.java:129) ~[spring-data-keyvalue-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) ~[spring-data-commons-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) ~[spring-data-commons-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) ~[spring-data-commons-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at com.sun.proxy.$Proxy47.findById(Unknown Source) ~[na:na]
    at com.test.redisbug.RedisBugApplication.run(RedisBugApplication.java:29) ~[classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) ~[spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
    ... 5 common frames omitted
Caused by: java.lang.UnsupportedOperationException: No accessor to set property @org.springframework.data.redis.core.TimeToLive(unit=SECONDS)private final java.lang.Long com.test.redisbug.Token.expiration!
    at com.test.redisbug.Token_Accessor_wgdh2l.setProperty(Unknown Source) ~[classes/:na]
    at org.springframework.data.redis.core.RedisKeyValueAdapter.readBackTimeToLiveIfSet(RedisKeyValueAdapter.java:622) ~[spring-data-redis-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.redis.core.RedisKeyValueAdapter.get(RedisKeyValueAdapter.java:300) ~[spring-data-redis-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.keyvalue.core.KeyValueTemplate.lambda$findById$3(KeyValueTemplate.java:253) ~[spring-data-keyvalue-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.data.keyvalue.core.KeyValueTemplate.execute(KeyValueTemplate.java:346) ~[spring-data-keyvalue-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    ... 29 common frames omitted

我将实体上的 @Value 注释更改为 @Data @AllArgsConstructor,现在它可以正常工作了。

spring-data-redis 好像有一些变化。

【讨论】:

【参考方案2】:

把变量key的名字改成id。

有一个错误使得带有@Id 注释的字段必须命名为 id。

public class Token implements Serializable 
    @Id private String id;
    private String code;
    @TimeToLive private Long expiration;

【讨论】:

【参考方案3】:

我刚刚遇到了同样的错误,并通过在我的 kotlin 模型中将 val 设置为 var 来解决问题。我没有使用@value@Data@AllArgsConstructor

@RedisHash("keys")
class Token (
        @Id
        val key: String? = null,
        @TimeToLive
        var expiration: Long
)

我的日志如下所示:

org.springframework.data.keyvalue.core.UncategorizedKeyValueException: No accessor to set property @org.springframework.data.redis.core.TimeToLive(unit=SECONDS)private final long oauth2demo.oauth2clientdemo.Token.expiration!; nested exception is java.lang.UnsupportedOperationException: No accessor to set property @org.springframework.data.redis.core.TimeToLive(unit=SECONDS)private final long oauth2demo.oauth2clientdemo.Token.expiration!
    at org.springframework.data.keyvalue.core.KeyValuePersistenceExceptionTranslator.translateExceptionIfPossible(KeyValuePersistenceExceptionTranslator.java:55) ~[spring-data-keyvalue-2.1.9.RELEASE.jar!/:2.1.9.RELEASE]
    at org.springframework.data.keyvalue.core.KeyValueTemplate.resolveExceptionIfPossible(KeyValueTemplate.java:462) ~[spring-data-keyvalue-2.1.9.RELEASE.jar!/:2.1.9.RELEASE]
    at org.springframework.data.keyvalue.core.KeyValueTemplate.execute(KeyValueTemplate.java:348) ~[spring-data-keyvalue-2.1.9.RELEASE.jar!/:2.1.9.RELEASE]
    at org.springframework.data.keyvalue.core.KeyValueTemplate.findById(KeyValueTemplate.java:251) ~[spring-data-keyvalue-2.1.9.RELEASE.jar!/:2.1.9.RELEASE]
    at org.springframework.data.keyvalue.repository.support.SimpleKeyValueRepos
...

【讨论】:

以上是关于Spring Boot 2.1.0 和 Java 11 上的 Spring Data Redis 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2.1.0 和 Flyway 4.2.0

Spring Boot 2.1.0 已发布,7 个重大更新你需要了解

重磅Spring Boot 2.1.0 权威发布

Spring Boot Admin 2.1.0 学习笔记

关闭 Spring Boot AWS 自动配置

Spring-Boot Banner