KryoException。由于无限递归而发生 Stackoverflow

问题描述 投票:0回答:1

我有一个项目,我使用 RedissonSpringCacheManager 和 RedissonClient 默认配置。 我正在使用@Cacheable注释来缓存实体(不幸的是,目前我无法缓存DTO而不是实体,因为项目太大。我也无法修改实体中的关联)。

请检查示例代码以更好地解释我遇到的问题:

具有双向关联的实体:

@Entity
public class User implements Serializable {
    @Id
    @Column(name = "user_id")
    private Long id;
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade = CascadeType.ALL)
    private Set<Address> addresses
}

@Entity
@Table(name = "address")
public class Address implements Serializable { 
    @Id
    private Long id;
    @ManyToOne
    @JoinColumn(name = "user_id", referencedColumnName = "user_id", nullable = false)
    private User user;
}

缓存配置:

@Bean
CacheManager cacheManager(RedissonClient redissonClient) {
    Map<String,CacheConfig> config = new HashMap<>();
    config.put(users, new CacheConfig(liveTime, idleTime));
    return new RedissonSpringCacheManager(redissonClient, config);
}

用于缓存的方法:

@Cacheable(cacheNames = users, key = "#p0", condition = "#p0 != null", unless = "#result == null")
public User findById(Long id) {
    return userRepository.findById(id);
}

Redisson 版本 3.17.1 可以正常工作 升级到 redisson 3.23.1 后,我在实体序列化方面遇到了这样的异常(当尝试将用户添加到缓存中时,通过调用方法

findById
):

com.esotericsoftware.kryo.KryoException: A StackOverflow occurred. The most likely cause is that your data has a circular reference resulting in infinite recursion. Try enabling references with Kryo.setReferences(true). If your data structure is really more than 1320 levels deep then try increasing your Java stack size. Serialization trace:
addresses (com.test.User)
user (com.test.Address)
addresses (com.test.User)
user (com.test.Address)
addresses (com.test.User)
...

我已经尝试过的是:

1)

通过扩展 Kryo5Codec 并使用自定义 kodec 来设置引用

public class CustomKryo5Codec extends Kryo5Codec {
    @Override
    protected Kryo createKryo(ClassLoader classLoader) {
        Kryo kryo = super.createKryo(classLoader);
        kryo.setReferences(true);
        return kryo;
    }
}

缓存配置改变了

return new RedissonSpringCacheManager(redissonClient, config); 

return new RedissonSpringCacheManager(redissonClient, config, new CustomKryo5Codec());

在此更改之后,我可以成功地将实体保存在缓存中,但我无法读取它,因为 org.hibernate.LazyInitializationException:无法延迟初始化集合,无法初始化代理 - 无会话

2)

将编解码器从 Kryo 更改为 MarshallingCodec,这是 redisson 3.17.1 中默认使用的。 在缓存配置改变了

return new RedissonSpringCacheManager(redissonClient, config); 

return new RedissonSpringCacheManager(redissonClient, config, new MarshallingCoded());

此更改后,缓存按预期工作,但我仍然不确定这是否是最佳解决方案。

请问还有其他好的解决方法吗?

spring recursion redis kryo redisson
1个回答
0
投票

这个问题已经为您解决了吗?我在尝试使用 RMap 和 Redisson 客户端编写 Map 时遇到类似的异常

© www.soinside.com 2019 - 2024. All rights reserved.