Estoy tratando de usar Redis Cache para mejorar el rendimiento de nuestra aplicación. Me refiero a este artículo para mi implementación. Estoy recibiendo esta excepción:
class com.entity.UserEntity cannot be cast to class com.entity.UserEntityRedisConfig:
@Configuration @EnableCaching public class RedisConfig { @Value("${spring.redis.port}") int redisPort; @Value("${spring.redis.host}") String redisHost; @Bean public LettuceConnectionFactory redisLettuceConnectionFactory() { RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(redisHost,redisPort); return new LettuceConnectionFactory(redisStandaloneConfiguration); } @Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisLettuceConnectionFactory()); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new JdkSerializationRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); redisTemplate.setEnableTransactionSupport(true); redisTemplate.afterPropertiesSet(); return redisTemplate; } }Entidad usuaria:
@Entity @Getter @Setter @EqualsAndHashCode(callSuper=false) @Slf4j @Table(name="user") public class UserEntity extends BaseEntity implements Serializable { private static final long serialVersionUID = 1L; @Id @Column(name = "user_id") @Type(type = "uuid-char") private UUID userId;//Binary in DB and UUID here @OneToMany(fetch = FetchType.EAGER, mappedBy = "user", orphanRemoval = true, cascade= CascadeType.ALL) @JsonIgnore @ToStringExclude @Fetch(value = FetchMode.SUBSELECT) private List<EmailAddress> emailAddresses = new ArrayList<>(); . . . }UserDaoImpl
@Repository public class UserDaoImpl implements UserDao { private UserRepository userRepository; private HashOperations hashOperations; //to access Redis cache private static final String KEY = "User"; public UserDaoImpl(@Autowired RedisTemplate<String, Object> redisTemplate, @Autowired UserRepository userRepository) { this.userRepository = userRepository; hashOperations = redisTemplate.opsForHash(); } @Override public Optional<UserEntity> fetchUserById(String userId) throws Exception { // Getting Exception here (UserEntity) hashOperations.get(KEY,userId) UserEntity userEntity = (UserEntity) hashOperations.get(KEY,userId); Optional<UserEntity> userOptional = Optional.ofNullable(userEntity); if(!userOptional.isPresent()) { userOptional = userRepository.findByUserId(userId); if (userOptional.isPresent()) { System.out.println("Cache Miss User id:" + userOptional.get().getUserId()); hashOperations.put(KEY, userOptional.get().getUserId().toString(), userOptional.get()); } else { throw new Exception("User not present"); } } return userOptional; } }Puedo colocar correctamente UserEntity en el caché, pero luego, al recuperarlo, obtengo la excepción mencionada anteriormente. Lo más probable es que el problema se deba a Hibernate. Cuando almacenamos en caché la entidad por primera vez, coloca Proxy/PersistentBag en lugar de Colecciones, por lo que la próxima vez (en alguna otra sesión) cuando recuperemos el Objeto de Caché, no podremos enviarlo a la entidad requerida. ¿Alguien puede confirmar que este es el problema, en caso afirmativo, cómo resolverlo?
Hibernate decora la clase, lo que probablemente esté causando el problema, además hay referencias importantes a la base de datos subyacente.
Recomiendo encarecidamente (ya sea que use Redis o no) definir una versión POJO de su entidad y convertir la clase de entidad en POJO lo antes posible, y convertir POJO en la entidad lo más tarde posible, para que su aplicación se ocupe de POJOs, y recibe, valida y emite (desde su API) POJOs, y la entidad solo se usa al interactuar con la base de datos.
Almacene instancias de POJO en Redis en lugar de instancias de entidad.
O para ser más robusto, serialice su POJO a json y almacene la cadena json en redis, deserializándola en el camino de regreso. Jackson (que viene gratis con Spring Boot, admite esto de fábrica. Es muy simple de implementar, además puede depurar fácilmente el contenido en Redis mediante la inspección visual de su contenido.