我的Spring Boot项目使用
spring-boot-starter-data-redis
在redis上进行缓存,Oracle数据库进行持久化。它与当前版本 2.7.6 完美运行。我刚刚升级到3.0.5。源代码确实发生了很大变化,但 redis 的配置保持不变:
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.builder(redisConnectionFactory)
.transactionAware()
.build();
}
这是我的使用方法
@Cacheable
@Autowired
private ConfRepository confRepository;
@Cacheable(value = "configCache", key = "{#root.methodName, #key}")
@Override
public Optional<Config> getByKey(String key) {
return confRepository.findByKey(key);
}
我用 2 个实例部署我的服务。问题是,当实例 1 中的
key
被放入 Cacheable
时,实例 2 无法反序列化,即在上面的方法中,我对实例 1 的第一个请求使用密钥 getByKey
到 key1
,我的第二个请求是实例 2 也带有 key1
应该命中缓存(从 redis 获取值并返回),但我得到了堆栈跟踪:
org.springframework.data.redis.serializer.SerializationException: Cannot deserialize
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:84)
at org.springframework.data.redis.serializer.DefaultRedisElementReader.read(DefaultRedisElementReader.java:46)
at org.springframework.data.redis.serializer.RedisSerializationContext$SerializationPair.read(RedisSerializationContext.java:272)
at org.springframework.data.redis.cache.RedisCache.deserializeCacheValue(RedisCache.java:277)
at org.springframework.data.redis.cache.RedisCache.lookup(RedisCache.java:92)
at org.springframework.cache.support.AbstractValueAdaptingCache.get(AbstractValueAdaptingCache.java:58)
at org.springframework.cache.transaction.TransactionAwareCacheDecorator.get(TransactionAwareCacheDecorator.java:80)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:73)
at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:571)
at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:536)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:402)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:345)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:702)
at vn.com.tcbs.h2h.biz.service.impl.ConfigManagerServiceImpl$$SpringCGLIB$$0.getGroupRole(<generated>)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:211)
at jdk.proxy2/jdk.proxy2.$Proxy201.getGroupRole(Unknown Source)
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78)
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36)
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:82)
... 219 common frames omitted
Caused by: java.lang.IllegalStateException: Could not identify any active SessionFactory having UUID 0105e7c4-c59a-46a6-a86e-23a65dde6ed6
at org.hibernate.proxy.pojo.bytebuddy.SerializableProxy.retrieveMatchingSessionFactory(SerializableProxy.java:127)
at org.hibernate.proxy.pojo.bytebuddy.SerializableProxy.readResolve(SerializableProxy.java:113)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1190)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2266)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1733)
at java.base/java.io.ObjectInputStream$FieldValues.<init>(ObjectInputStream.java:2606)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2457)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2257)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1733)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:509)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:467)
at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:71)
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:73)
... 221 common frames omitted
在这种情况下有人可以帮助我吗?
问题是在 Hibernate 6 中,hibernate 对象缓存不起作用。因此,如果它是
FetchType.Lazy
并且您需要 Lazy 对象属性和 unproxy
缓存之前的对象,则需要加载完整的对象。
要取消代理对象,请使用
Hibernate.unproxy
方法。
更新代码:
@Cacheable(value = "configCache", key = "{#root.methodName, #key}")
@Override
public Optional<Config> getByKey(String key) {
var config = confRepository.findByKey(key);
var entity = config.isPresent() ? Hibernate.unproxy(config.get(), Config.class) : null;
return Optional.ofNullable(entity);
}
在 Spring MVC 中升级到 Hibernate 6 后,我遇到了类似的问题。通过
unproxy
将 hibernate 对象保存到缓存中解决了这个问题。另外,通过 Spring Security 会话,我需要使用记录/POJO 类作为身份验证对象。
如果问题仍然存在,则使用记录/POJO 类存储在缓存中。因为不同实体的映射也会在序列化中添加hibernate类。
Hibernate 6:当多个服务器使用相同的缓存时,切勿将 hibernate 对象存储到缓存。
您可以使用RedisInsight浏览存储在redis中的数据并检查以获取更多详细信息。
如果一个实例中的实体字段与另一实例中的实体字段不同,也可能会发生异常
因此,如果您的实例从不同的分支运行,请检查实体的字段。