Spring boot 整合redis时,使用@Cacheable实现redis实现缓存时,如果出现单线程时无报错。但是高并发的状态之下却出现报null情况。 遇到该问题时,可以升级spring-data-redis的版本即可 会BUG在1.8.11以上的版本得到修复。
具体原因如下(参考别人的文章): 在使用注解获取缓存的时候,RedisCache的get方法会先去判断key是否存在,然后再去获取值。这了就有一个漏铜,当线程1判断了key是存在的,紧接着这个时候这个key过期了,这时线程1再去获取值的时候返回的是null。
RedisCache的get方法源码:
public RedisCacheElement get(final RedisCacheKey cacheKey) {
Assert.notNull(cacheKey, "CacheKey must not be null!");
// 判断Key是否存在
Boolean exists = (Boolean) redisOperations.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.exists(cacheKey.getKeyBytes());
}
});
if (!exists.booleanValue()) {
return null;
}
// 获取key对应的值
return new RedisCacheElement(cacheKey, fromStoreValue(lookup(cacheKey)));
}
// 获取值
protected Object lookup(Object key) {
RedisCacheKey cacheKey = key instanceof RedisCacheKey ? (RedisCacheKey) key : getRedisCacheKey(key);
byte[] bytes = (byte[]) redisOperations.execute(new AbstractRedisCacheCallback<byte[]>(
new BinaryRedisCacheElement(new RedisCacheElement(cacheKey, null), cacheValueAccessor), cacheMetadata) {
@Override
public byte[] doInRedis(BinaryRedisCacheElement element, RedisConnection connection) throws DataAccessException {
return connection.get(element.getKeyBytes());
}
});
return bytes == null ? null : cacheValueAccessor.deserializeIfNecessary(bytes);
}