使用 RedisTemplate 和 GenericJackson2RedisSerializer 读取值时出现序列化错误

Serialization Error when reading value with RedisTemplate and GenericJackson2RedisSerializer

我正在尝试 Spring Data Redis 的一个非常基本的例子,我想在 Redis 中存储一个用户对象,然后 return 它:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
class BasicUser {
        private String name;
        private String surname;
        private String emailAddress;
        private Integer age;
}
@Test
    public void storeUserInRedisWithRedisTemplateTest() {
        BasicUser user = BasicUser
                        .builder()
                        .age(22)
                        .name("testuser")
                        .surname("testsurname")
                        .emailAddress("address@address.com")
                        .build();

        redisTemplate.opsForValue().set("userWithTemplate", user, 10800);

        BasicUser returnedUser =  (BasicUser) redisTemplate.opsForValue().get("userWithTemplate");
        assertThat(returnedUser.emailAddress, is(user.emailAddress));
    }

错误是:

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Invalid UTF-32 character 0x7b214063 (above 0x0010ffff) at char #2700, byte #10803); nested exception is java.io.CharConversionException: Invalid UTF-32 character 0x7b214063 (above 0x0010ffff) at char #2700, byte #10803)

    at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.deserialize(GenericJackson2JsonRedisSerializer.java:152)
    at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.deserialize(GenericJackson2JsonRedisSerializer.java:130)
    at org.springframework.data.redis.core.AbstractOperations.deserializeValue(AbstractOperations.java:335)
    at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:61)
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:228)
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:188)
    at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:96)
    at org.springframework.data.redis.core.DefaultValueOperations.get(DefaultValueOperations.java:53)
    at com.kuluvalley.guru.server.service.UserSessionCacheServiceTest.storeUserInRedisWithRedisTemplateTest(UserSessionCacheServiceTest.java:123)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: java.io.CharConversionException: Invalid UTF-32 character 0x7b214063 (above 0x0010ffff) at char #2700, byte #10803)
    at com.fasterxml.jackson.core.io.UTF32Reader.reportInvalid(UTF32Reader.java:195)
    at com.fasterxml.jackson.core.io.UTF32Reader.read(UTF32Reader.java:158)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._loadMore(ReaderBasedJsonParser.java:250)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._skipWSOrEnd(ReaderBasedJsonParser.java:2354)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:672)
    at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4340)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4189)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3266)
    at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.deserialize(GenericJackson2JsonRedisSerializer.java:150)
    ... 40 more

在 Redis 中,值如下所示:

[MANY MORE 0x00]
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\"@class\":\"com.org.BasicUser\",\"name\":\"testuser\",\"surname\":\"testsurname\",\"emailAddress\":\"address@address.com\",\"age\":22}"

相关Redis配置如下:

@Configuration
public class RedisConfig {

    @Bean
    public RedisConnectionFactory redisConnectionFactory(Environment env) {
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setHostName(env.getRequiredProperty("redis.hostname"));
        configuration.setPort(env.getProperty("redis.port", Integer.class, 6379));
        return new LettuceConnectionFactory(configuration);
    }

    @Bean
    public StringRedisTemplate redisTemplate(Environment env) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory(env));
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }

}

我希望它能在我读取和写入相同数据时正常工作。数量 0x00 也令人担忧。使用字符串作为值是最佳实践吗?我错过了什么?

基本上是因为你用错了api没想到:

  • void set(K key, V value, long offset);

你应该使用:

  • void set(K key, V value, long timeout, TimeUnit unit);

使用代码:

  • redisTemplate.opsForValue().set("userWithTemplate", user, 10800, TimeUnit.SECONDS);