为了账号安全,请及时绑定邮箱和手机立即绑定

具有复杂密钥的 SpringData Redis 存储库

具有复杂密钥的 SpringData Redis 存储库

慕森卡 2024-01-05 14:40:29
CrudRepository我们尝试在项目中使用 Spring Data来为域对象提供持久性。首先,我选择 REDIS 作为后端,因为在第一次实验中CrudRepository<ExperimentDomainObject, String>,它的运行似乎很容易。当尝试将其放入我们的生产代码中时,事情变得更加复杂,因为这里我们的域对象不需要使用简单类型作为密钥,因此存储库是CrudRepository<TestObject, ObjectId>.现在我得到了例外:找不到能够从类型 [...ObjectId] 转换为类型 [byte[]] 的转换器寻找这个异常,这个答案导致我对RedisTemplate配置进行了未经教育的实验。(对于我的实验,我使用的是 emdedded-redis)我的想法是,提供一个RedisTemplate<Object, Object>而不是RedisTemplate<String, Object>允许使用Jackson2JsonRedisSerializerkeySerializer 来完成工作。尽管如此,调用还是testRepository.save(testObject)失败。请看我的代码:为了简洁起见,我有公共字段并省略了导入。如果需要它们(使其成为 MVCE),我将很乐意提供它们。请给我留言。依赖项:dependencies {    implementation 'org.springframework.boot:spring-boot-starter-data-redis'    implementation 'org.springframework.boot:spring-boot-starter-web'    compileOnly 'org.projectlombok:lombok'    annotationProcessor 'org.projectlombok:lombok'    implementation group: 'redis.clients', name: "jedis", version: '2.9.0'    implementation group: 'it.ozimov', name: 'embedded-redis', version: '0.7.2'}Redis配置:@Configuration@EnableRedisRepositoriespublic class RedisConfiguration {    @Bean    JedisConnectionFactory jedisConnectionFactory() {        return new JedisConnectionFactory();    }}不是想要的答案:当然,我可能会引入一些特殊的 ID,它是一种简单的数据类型,例如我使用 jacksons ObjectMapper 手动构建的 JSON-String,然后使用CrudRepository<TestObject, String>.同时我也尝试过:RedisTemplate<String, String>RedisTemplate<String, Object>自动装配 aRedisTemplate并设置其默认序列化器注册一个Converter<ObjectId, byte[]>到自动装配的ConverterRegistry一个自动接线GenericConversionService,但显然他们是错误的。
查看完整描述

1 回答

?
皈依舞

TA贡献1851条经验 获得超3个赞

基本上,Redis 存储库使用RedisKeyValueTemplate底层将数据存储为键(Id)和值对。所以除非你直接使用它,否则你的配置RedisTemplate将不起作用。


因此,您的一种方法是RedistTemplate直接使用,这样的东西对您有用。


@Service

public class TestService {


    @Autowired

    private RedisTemplate redisTemplate;


    public void saveIt(TestObject testObject){

        ValueOperations<ObjectId, TestObject> values = redisTemplate.opsForValue();

        values.set(testObject.testId, testObject);

    }


}

因此,上面的代码将使用您的配置并使用 Jackson 作为键和值的映射器在 Redis 中生成字符串对。


但是,如果您想通过以下方式使用 Redis 存储库,则需要为from 和 toCrudRepository创建读写转换器,并将它们注册为自定义 Redis 转换。ObjectIdStringbyte[]


ObjectId因此,让我们为<->创建读写转换器String


读者


@Component

@ReadingConverter

@Slf4j

public class RedisReadingStringConverter implements Converter<String, ObjectId> {


    private ObjectMapper objectMapper = new ObjectMapper();


    @Override

    public ObjectId convert(String source) {

        try {

            return objectMapper.readValue(source, ObjectId.class);

        } catch (IOException e) {

            log.warn("Error while converting to ObjectId.", e);

            throw new IllegalArgumentException("Can not convert to ObjectId");

        }

    }

}

作家


@Component

@WritingConverter

@Slf4j

public class RedisWritingStringConverter implements Converter<ObjectId, String> {


    private ObjectMapper objectMapper = new ObjectMapper();


    @Override

    public String convert(ObjectId source) {

        try {

            return objectMapper.writeValueAsString(source);

        } catch (JsonProcessingException e) {

            log.warn("Error while converting ObjectId to String.", e);

            throw new IllegalArgumentException("Can not convert ObjectId to String");

        }

    }

}

以及 ObjectId <-> byte[] 的读写转换器


作家


@Component

@WritingConverter

public class RedisWritingByteConverter implements Converter<ObjectId, byte[]> {


    Jackson2JsonRedisSerializer<ObjectId> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(ObjectId.class);


    @Override

    public byte[] convert(ObjectId source) {

        return jackson2JsonRedisSerializer.serialize(source);

    }

}

读者


@Component

@ReadingConverter

public class RedisReadingByteConverter implements Converter<byte[], ObjectId> {


     Jackson2JsonRedisSerializer<ObjectId> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(ObjectId.class);


    @Override

    public ObjectId convert(byte[] source) {

        return jackson2JsonRedisSerializer.deserialize(source);

    }

}

最后添加 Redis 自定义对话。只需将代码放入RedisConfiguration


@Bean

public RedisCustomConversions redisCustomConversions(RedisReadingByteConverter readingConverter,

                                                     RedisWritingByteConverter redisWritingConverter,

                                                     RedisWritingStringConverter redisWritingByteConverter,

                                                     RedisReadingStringConverter redisReadingByteConverter) {

    return new RedisCustomConversions(Arrays.asList(readingConverter, redisWritingConverter, redisWritingByteConverter, redisReadingByteConverter));

}

因此,现在在创建转换器并将其注册为自定义 Redis 转换器后,您RedisKeyValueTemplate可以使用它们,并且您的代码应该按预期工作。


查看完整回答
反对 回复 2024-01-05
  • 1 回答
  • 0 关注
  • 80 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信