我正在尝试使用Redis缓存来提高我们的应用程序的性能。我引用了这个article作为我的实现。我得到了这个异常:
class com.entity.UserEntity cannot be cast to class com.entity.UserEntity
重新配置:
@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;
}
}
用户实体:
@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<>();
.
.
.
}
用户道实现
@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;
}
}
我可以成功地将UserEntity该高速缓存中,但是在检索时,我遇到了上面提到的异常。最有可能的原因是Hibernate。当我们第一次缓存实体时,它会将Proxy/PersistentBag放在Collections的位置,所以下次(在其他会话中)当我们从缓存中检索对象时,我们无法将其转换为所需的实体。是否有人确认这是问题所在?如果是,如何解决?
2条答案
按热度按时间ccrfmcuu1#
Hibernate会装饰类,这可能是导致问题的原因,另外还有对底层数据库的重量级引用。
我强烈建议(无论你是否使用Redis)定义一个POJO版本的实体,并尽可能早地将实体类转换为POJO,尽可能晚地将POJO转换为实体,这样你的应用程序就可以处理POJO,并接收、验证和发出(从它的API)POJO,而且实体 * 只 * 在与数据库交互时使用。
在Redis中存储POJO示例,而不是实体示例。
或者为了更健壮,将POJO序列化为json,并将json字符串存储在Redis中,在返回的途中将其反序列化。Jackson(它随spring Boot 免费提供,支持开箱即用。它的实现非常简单,* 另外 * 您可以通过视觉检查内容来轻松调试Redis中的内容。
doinxwow2#
我已经找到了这个问题的解决方案。我犯了一个错误。我找到的唯一答案是这个Hibernate修饰的实体导致了问题。它与Hibernate一点关系都没有。当我们创建redisTemplate时,我们还添加了键和值序列化。我添加了错误的序列化。
默认情况下,序列化是JDK,这是必需的。我没有使用它,也没有添加StringSerialization,所以数据在REDIS中是以String格式存储的。所以当我们执行反序列化时,我们需要实现反序列化器。
有关序列化的更多详细信息,请参阅以下链接https://medium.com/@betul5634/redis-serialization-with-spring-redis-data-lettuce-codec-1a1d2bc73d26