spring jpa元组不可序列化

pbpqsu0x  于 2021-06-08  发布在  Redis
关注(0)|答案(1)|浏览(492)

我有一个springboot2.3应用程序。我使用springjpa对mysql进行查询。我还利用了redis。

@Cacheable(cacheNames = "documents#chartrevenuebymonthperuser")
    @Transactional(readOnly = true)
    @Query("Here there is my query")
    List<Tuple> chartRevenueByMonthPerUser(@Param("from") LocalDate from, @Param("until") LocalDate until, @Nullable @Param("storeId") Long storeId);

我更喜欢 List<Tuple> 而不是 List<Object[]> 但不幸的是redis说元组是不可序列化的。元组来自包 javax.persistence 您有什么好的建议来利用tuple允许redis缓存结果吗?

9w11ddsr

9w11ddsr1#

redis缓存可以配置为使用其他序列化程序/反序列化程序。
元组接口不提供任何getter/setter等,所以序列化失败,尽管您可以定义应该实现元组接口的元组。

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
class TupleMsg implements Tuple {
  private Object[] tuple;

  @Override
  public <T> T get(int i, Class<T> type) {
    final Object result = get(i);
    if (result != null && !type.isInstance(result)) {
      throw new IllegalArgumentException(
          String.format(
              "Requested tuple value [index=%s, realType=%s] cannot be assigned to requested type [%s]",
              i, result.getClass().getName(), type.getName()));
    }
    return (T) result;
  }

  @Override
  public Object get(int i) {
    if (i < 0) {
      throw new IllegalArgumentException("requested tuple index must be greater than zero");
    }
    if (i >= tuple.length) {
      throw new IllegalArgumentException("requested tuple index exceeds actual tuple size");
    }
    return tuple[i];
  }

  @Override
  public Object[] toArray() {
    return tuple;
  }

  @Override
  public <X> X get(TupleElement<X> tupleElement) {
    throw new NotImplementedException();
  }

  @Override
  public <X> X get(String alias, Class<X> type) {
    throw new NotImplementedException();
  }

  @Override
  public Object get(String alias) {
    throw new NotImplementedException();
  }

  @Override
  public List<TupleElement<?>> getElements() {
    throw new NotImplementedException();
  }
}

此接口中的某些方法尚未实现,如果您认为需要,可以实现它们。

class MyRedisSerializer implements RedisSerializer<Object> {
    private GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer =
        new GenericJackson2JsonRedisSerializer();

    @Override
    public byte[] serialize(Object t) throws SerializationException {
      if (t instanceof Tuple) {
        TupleMsg msg = new TupleMsg(((Tuple) t).toArray());
        return jackson2JsonRedisSerializer.serialize(msg);
      }
      return jackson2JsonRedisSerializer.serialize(t);
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
      if (SerializationUtils.isEmpty(bytes)) {
        return null;
      }
      try {
        return jackson2JsonRedisSerializer.deserialize(bytes);
      } catch (Exception e) {
        log.warn("Jackson deserialization has failed {}", new String(bytes), e);
        return new String(bytes);
      }
    }
  }

一旦实现了元组和重序列化程序,就可以使用它们来配置缓存。

@Configuration
@EnableCaching
public class RedisCacheManagerConfiguration {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public CacheManager redisCacheManager() {
        RedisSerializationContext.SerializationPair<Object> jsonSerializer = 
         RedisSerializationContext.SerializationPair.fromSerializer(new MyRedisSerializer());
         return RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(redisConnectionFactory)
                .cacheDefaults(
                    RedisCacheConfiguration.defaultCacheConfig()
                            .entryTtl(Duration.ofDays(1))
                            .serializeValuesWith(jsonSerializer)
                )
                .build();
    }

}

这就是你要做的一切。

相关问题