You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot集成Redis缓存:transactionAware为true时超时如何跳过缓存

问题根因

当你将RedisCacheManager的transactionAware设置为true时,缓存操作会被绑定到Spring事务同步流程中,在事务提交/回滚阶段执行,该场景下默认的CacheErrorHandler不会被触发,因此你之前的异常降级方案失效。

解决方案:自定义容错RedisCache实现

通过自定义RedisCache子类拦截所有缓存操作的异常,捕获Redis相关故障后直接跳过缓存逻辑,不向上抛出异常,即可实现不中断业务流程的需求,不受transactionAware配置影响。

实现步骤

  1. 自定义容错RedisCache类,重写所有缓存操作方法,捕获异常降级
import org.springframework.cache.Cache.ValueRetrievalException;
import org.springframework.dao.QueryTimeoutException;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Callable;

public class FaultTolerantRedisCache extends RedisCache {
    private static final Logger log = LoggerFactory.getLogger(FaultTolerantRedisCache.class);

    protected FaultTolerantRedisCache(String name, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig) {
        super(name, cacheWriter, cacheConfig);
    }

    @Override
    public ValueWrapper get(Object key) {
        try {
            return super.get(key);
        } catch (Exception e) {
            handleCacheError("get", key, e);
            return null;
        }
    }

    @Override
    public <T> T get(Object key, Class<T> type) {
        try {
            return super.get(key, type);
        } catch (Exception e) {
            handleCacheError("get", key, e);
            return null;
        }
    }

    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        try {
            return super.get(key, valueLoader);
        } catch (Exception e) {
            handleCacheError("get", key, e);
            try {
                return valueLoader.call();
            } catch (Exception ex) {
                throw new ValueRetrievalException(key, valueLoader, ex);
            }
        }
    }

    @Override
    public void put(Object key, Object value) {
        try {
            super.put(key, value);
        } catch (Exception e) {
            handleCacheError("put", key, e);
        }
    }

    @Override
    public void evict(Object key) {
        try {
            super.evict(key);
        } catch (Exception e) {
            handleCacheError("evict", key, e);
        }
    }

    @Override
    public void clear() {
        try {
            super.clear();
        } catch (Exception e) {
            handleCacheError("clear", null, e);
        }
    }

    private void handleCacheError(String operation, Object key, Exception e) {
        // 只处理Redis相关异常,其他异常正常抛出避免业务异常被掩盖
        if (e instanceof QueryTimeoutException || e.getCause() instanceof io.lettuce.core.RedisException) {
            log.warn("Redis缓存[{}]操作失败,key={},跳过缓存逻辑:{}", operation, key, e.getMessage());
        } else {
            throw e;
        }
    }
}
  1. 自定义RedisCacheManager,创建上述容错缓存实例
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import java.util.Map;

public class FaultTolerantRedisCacheManager extends RedisCacheManager {

    public FaultTolerantRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, Map<String, RedisCacheConfiguration> initialCacheConfigurations) {
        super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations);
    }

    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
        return new FaultTolerantRedisCache(name, getCacheWriter(), cacheConfig != null ? cacheConfig : getDefaultCacheConfiguration());
    }
}
  1. 修改原配置类,替换默认的RedisCacheManager为自定义实现
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
    RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
    return new FaultTolerantRedisCacheManager(
        cacheWriter,
        buildDefault(),
        buildFromSettings()
    )
    // 保留原有的事务感知配置
    .setTransactionAware(true)
    .build();
}
注意事项
  • 缓存读取失败时返回null,相当于缓存未命中,会直接走原业务方法查询数据,符合降级预期
  • 缓存写入/删除失败时直接跳过,不会影响主事务的提交执行
  • 可以根据业务需要调整异常拦截范围,比如加入Redis连接异常、集群故障等异常的判断

内容的提问来源于stack exchange,提问作者bobanman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 19:06:03