Spring-data-rediscacheable并发导致的null问题Spring-data-redis cacheable并发导致的null,版本低于1.8.11会导致该问题
1.8.11之前的版本通过@cacheable缓存获取内容,代码层⾯是先判断缓存key值是否存在,存在在进⾏get缓存值,这就会导致⾮原⼦性操作。
问题场景:(⾼并发情况下,多线程操作同⼀个key)
步骤:
1.线程1获取缓存值,刚判断key值存在
2.线程2在此期间删除了缓存中的该key值
3.线程1继续执⾏,这时候获取缓存中的key值为null
1.8.11版本⼀下源代码如下:
RedisCache类中的get⽅法:
public RedisCacheElement get(final RedisCacheKey cacheKey) {
Boolean exists = (ute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
KeyBytes());
}
});
return !exists ? null : new RedisCacheElement(cacheKey, this.fromStoreValue(this.lookup(cacheKey)));
}
解决⽅案⼀:
⾃定义RedisCache,覆写get⽅法
public class CustomRedisCache extends RedisCache {
@Override
public RedisCacheElement get(RedisCacheKey cacheKey) {
//获取值代码提前
RedisCacheElement redisCacheElement=new RedisCacheElement(cacheKey, this.fromStoreValue(this.lookup(cacheKey)))
Boolean exists = (ute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
KeyBytes());
}
});
if(!exists){
return null;
}
return redisCacheElement;
}
}
⾃定义 RedisCacheManager 覆写createCache⽅法
public class CustomRedisCacheManager extends RedisCacheManager {
private boolean cacheNullValues;
public CustomRedisCacheManager(RedisOperations redisOperations) {
super(redisOperations);
}
public CustomRedisCacheManager(RedisOperations redisOperations, Collection<String> cacheNames) {
super(redisOperations, cacheNames);
}
public CustomRedisCacheManager(RedisOperations redisOperations, Collection<String> cacheNames, boolean cacheNullValues) {
super(redisOperations, cacheNames, cacheNullValues);
this.cacheNullValues = cacheNullValues;
}
@Override
protected RedisCache createCache(String cacheName) {
long expiration = computeExpiration(cacheName);
return new CustomRedisCache(cacheName, (isUsePrefix() ? getCachePrefix().prefix(cacheName) : null), getRedisOperations(), expiration, cacheNullValues);
}
}
解决⽅案⼆:
讲spring-data-redis升级到1.8.11以上
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.22</version>
</dependency>
1.8.22版本源码如下:
public RedisCacheElement get(final RedisCacheKey cacheKey) {cacheable
Boolean exists = (ute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
KeyBytes());
}
});
if (!exists) {
return null;
} else {
byte[] bytes = this.doLookup(cacheKey);
return bytes == null ? null : new RedisCacheElement(cacheKey, this.fromStoreValue(this.deserialize(bytes)));
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论