【问题标题】:Update entity in redis with spring-data-redis使用 spring-data-redis 更新 redis 中的实体
【发布时间】:2018-06-15 10:26:24
【问题描述】:

我目前正在将 Redis (3.2.100) 与 Spring data redis (1.8.9) 和 Jedis 连接器一起使用。 当我在现有实体上使用 save() 函数时,Redis 会删除我的实体并重新创建实体。

在我的情况下,我需要保留这个现有实体并且只更新实体的属性。 (我有另一个线程同时读取同一个实体)

在 Spring 文档 (https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#redis.repositories.partial-updates) 中,我发现了部分更新功能。不幸的是,文档中的示例使用了 RedisTemplate 的 update() 方法。但这种方法不存在。

那么你曾经使用过 Spring-data-redis 部分更新吗?

还有没有delete之前更新实体redis的方法?

谢谢

【问题讨论】:

    标签: java spring redis spring-data spring-data-redis


    【解决方案1】:

    您应该使用 RedisKeyValueTemplate 进行部分更新。

    【讨论】:

      【解决方案2】:

      要获取RedisKeyValueTemplate,你可以这样做:

      @Autowired
      private RedisKeyValueTemplate redisKVTemplate;
      

      redisKVTemplate.update(实体)

      【讨论】:

      【解决方案3】:

      好吧,考虑关注文档 link 以及 spring 数据测试 (link) 实际上对最终解决方案的贡献为 0。

      考虑以下实体

      @RedisHash(value = "myservice/lastactivity")
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      @Builder
      public class LastActivityCacheEntity implements Serializable {
          @Id
          @Indexed
          @Size(max = 50)
          private String user;
          private long lastLogin;
          private long lastProfileChange;
          private long lastOperation;
      }
      

      假设:

      1. 我们不想在每次更新时都进行复杂的读写练习。

        entity = lastActivityCacheRepository.findByUser(userId); lastActivityCacheRepository.save(LastActivityCacheEntity.builder() .user(entity.getUser()) .lastLogin(entity.getLastLogin()) .lastProfileChange(entity.getLastProfileChange()) .lastOperation(entity.getLastOperation()).build()); 如果会弹出大约 100 行怎么办?然后在每个更新实体上获取并保存,效率很低,但仍然可以解决。

      2. 我们实际上并不希望使用 opsForHash + ObjectMapper + 配置 bean 方法进行复杂的练习 - 这很难实现和维护(例如 link

      所以我们要使用类似的东西:

      @Autowired
      private final RedisKeyValueTemplate redisTemplate;
      
      void partialUpdate(LastActivityCacheEntity update) {
        var partialUpdate = PartialUpdate
            .newPartialUpdate(update.getUser(), LastActivityCacheEntity.class);
        if (update.getLastLogin() > 0)
            partialUpdate.set("lastlastLogin", update.getLastLogin());
        if (update.getLastProfileChange() > 0)
            partialUpdate.set("lastProfileChange", update.getLastProfileChange());
        if (update.getLastOperation() > 0)
          partialUpdate.set("lastOperation", update.getLastOperation());
        redisTemplate.update(partialUpdate);
      }
      

      问题是 - 它不适用于这种情况。

      也就是说,值会更新,但您以后无法通过存储库实体查找查询新属性:某些 lastActivityCacheRepository.findAll() 将返回未更改的属性。

      解决办法如下:

      LastActivityCacheRepository.java

      @Repository
      public interface LastActivityCacheRepository extends CrudRepository<LastActivityCacheEntity, String>, LastActivityCacheRepositoryCustom {
          Optional<LastActivityCacheEntity> findByUser(String user);
      }
      

      LastActivityCacheRepositoryCustom.java

      public interface LastActivityCacheRepositoryCustom {
          void updateEntry(String userId, String key, long date);
      }
      

      LastActivityCacheRepositoryCustomImpl.java

      @Repository
      public class LastActivityCacheRepositoryCustomImpl implements LastActivityCacheRepositoryCustom {
          @Autowired
          private final RedisKeyValueTemplate redisKeyValueTemplate;
      
          @Override
          public void updateEntry(String userId, String key, long date) {
              redisKeyValueTemplate.update(new PartialUpdate<>(userId, LastActivityCacheEntity.class)
                  .set(key, date));
          }
      }
      

      最后是工作示例:

      void partialUpdate(LastActivityCacheEntity update) {
        if ((lastActivityCacheRepository.findByUser(update.getUser()).isEmpty())) {
            lastActivityCacheRepository.save(LastActivityCacheEntity.builder().user(update.getUser()).build());
        }
        if (update.getLastLogin() > 0) {
            lastActivityCacheRepository.updateEntry(update.getUser(),
                "lastlastLogin",
                update.getLastLogin());
        }
        if (update.getLastProfileChange() > 0) {
            lastActivityCacheRepository.updateEntry(update.getUser(),
                "lastProfileChange",
                update.getLastProfileChange());
        }
        if (update.getLastOperation() > 0) {
            lastActivityCacheRepository.updateEntry(update.getUser(),
                "lastOperation",
                update.getLastOperation());
      }
      

      感谢Chris Richardson 和他的src

      如果您不想在updateEntry 方法中将字段名称键入为字符串,则可以在实体类@FieldNameConstants 上使用lombok 注释。这会为您创建字段名称常量,然后您可以像这样访问您的字段名称:

      ...
            if (update.getLastOperation() > 0) {
                lastActivityCacheRepository.updateEntry(update.getUser(),
                    LastActivityCache.Fields.lastOperation, // <- instead of "lastOperation"
                    update.getLastOperation());
      ...
      

      这使得重构字段名称更加防错。

      【讨论】:

        猜你喜欢
        • 2012-06-24
        • 2021-09-13
        • 2022-10-05
        • 2015-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-01
        • 2022-08-03
        相关资源
        最近更新 更多