redis 无法将对象转换为实体类型

u0sqgete  于 2022-10-31  发布在  Redis
关注(0)|答案(2)|浏览(502)

我正在尝试使用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的位置,所以下次(在其他会话中)当我们从缓存中检索对象时,我们无法将其转换为所需的实体。是否有人确认这是问题所在?如果是,如何解决?

ccrfmcuu

ccrfmcuu1#

Hibernate会装饰类,这可能是导致问题的原因,另外还有对底层数据库的重量级引用。
我强烈建议(无论你是否使用Redis)定义一个POJO版本的实体,并尽可能早地将实体类转换为POJO,尽可能晚地将POJO转换为实体,这样你的应用程序就可以处理POJO,并接收、验证和发出(从它的API)POJO,而且实体 * 只 * 在与数据库交互时使用。
在Redis中存储POJO示例,而不是实体示例。
或者为了更健壮,将POJO序列化为json,并将json字符串存储在Redis中,在返回的途中将其反序列化。Jackson(它随spring Boot 免费提供,支持开箱即用。它的实现非常简单,* 另外 * 您可以通过视觉检查内容来轻松调试Redis中的内容。

doinxwow

doinxwow2#

我已经找到了这个问题的解决方案。我犯了一个错误。我找到的唯一答案是这个Hibernate修饰的实体导致了问题。它与Hibernate一点关系都没有。当我们创建redisTemplate时,我们还添加了键和值序列化。我添加了错误的序列化。

redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setHashKeySerializer(new StringRedisSerializer()) 
    redisTemplate.setHashKeySerializer(newJdkSerializationRedisSerializer());
    redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());

默认情况下,序列化是JDK,这是必需的。我没有使用它,也没有添加StringSerialization,所以数据在REDIS中是以String格式存储的。所以当我们执行反序列化时,我们需要实现反序列化器。
有关序列化的更多详细信息,请参阅以下链接https://medium.com/@betul5634/redis-serialization-with-spring-redis-data-lettuce-codec-1a1d2bc73d26

相关问题