跳转到内容

Spring缓存同步

来自代码酷

Spring缓存同步是Spring框架中用于解决多线程环境下缓存一致性的机制。当多个线程或分布式节点同时访问同一缓存数据时,可能出现脏读、过期数据或并发冲突问题。Spring通过注解驱动和底层抽象提供了一套优雅的同步解决方案。

概述[编辑 | 编辑源代码]

在分布式系统或高并发场景中,缓存同步确保所有线程或节点访问的数据是一致的。Spring通过以下方式实现同步:

  • @Cacheable + 锁机制
  • @CacheEvict 的同步清除
  • CacheManager 的底层协调

核心机制[编辑 | 编辑源代码]

基于注解的同步[编辑 | 编辑源代码]

Spring的缓存抽象层通过注解与AOP结合,在方法调用前后自动处理缓存同步。

  
@Cacheable(value = "users", key = "#id", sync = true)  
public User getUserById(Long id) {  
    return userRepository.findById(id).orElse(null);  
}
  • sync = true:启用同步锁,确保同一键值(如`#id`)的并发请求只有一个线程执行实际方法,其他线程等待结果。
  • 适用场景:高频读取但数据变更较少的场景(如用户基本信息)。

缓存清除同步[编辑 | 编辑源代码]

使用`@CacheEvict`确保数据更新时缓存立即失效:

  
@CacheEvict(value = "users", key = "#user.id")  
public void updateUser(User user) {  
    userRepository.save(user);  
}
  • 此操作是原子性的,Spring会阻塞其他线程直到缓存清除完成。

底层实现[编辑 | 编辑源代码]

Spring默认使用`ConcurrentMapCacheManager`,其同步行为依赖于`ConcurrentHashMap`的线程安全特性。对于分布式缓存(如Redis),需配置`RedisCacheManager`并启用事务支持:

  
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">  
    <property name="transactionAware" value="true"/>  
</bean>

实际案例[编辑 | 编辑源代码]

电商库存同步[编辑 | 编辑源代码]

在高并发下单场景中,使用`@Cacheable`同步防止超卖:

  
@Cacheable(value = "inventory", key = "#productId", sync = true)  
public Integer getStock(String productId) {  
    return inventoryService.getStock(productId);  
}  

@CacheEvict(value = "inventory", key = "#productId")  
public void deductStock(String productId, int quantity) {  
    inventoryService.deduct(productId, quantity);  
}

流程图解[编辑 | 编辑源代码]

sequenceDiagram participant Client1 participant Client2 participant Cache participant DB Client1->>Cache: getStock(101) (首次请求) Cache->>DB: 查询库存 DB-->>Cache: 库存=100 Cache-->>Client1: 100 Client2->>Cache: getStock(101) (并发请求) Cache->>Client2: 等待同步锁 Client1->>Cache: deductStock(101,1) Cache->>DB: 扣减库存 DB-->>Cache: 成功 Cache-->>Client1: OK Cache-->>Client2: 99 (返回更新后结果)

高级配置[编辑 | 编辑源代码]

自定义锁策略[编辑 | 编辑源代码]

通过实现`CacheInterceptor`扩展锁逻辑:

  
public class CustomCacheInterceptor extends CacheInterceptor {  
    @Override  
    protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {  
        if (isHighContentionKey(args)) {  
            Lock lock = getDistributedLock(args);  
            try {  
                lock.lock();  
                return super.execute(invoker, target, method, args);  
            } finally {  
                lock.unlock();  
            }  
        }  
        return super.execute(invoker, target, method, args);  
    }  
}

数学建模[编辑 | 编辑源代码]

对于缓存命中率与同步开销的权衡,可用以下公式表示: Ttotal=Tcache×p+(Tdb+Tsync)×(1p) 其中:

  • p:缓存命中率
  • Tsync:同步延迟时间

最佳实践[编辑 | 编辑源代码]

1. 对写多读少的数据禁用`sync`以避免锁竞争 2. 分布式环境使用Redis或Hazelcast等支持原子操作的缓存 3. 通过`@CacheConfig`统一配置同步策略

常见问题[编辑 | 编辑源代码]

模板:Q&A

模板:Q&A

通过上述机制,Spring缓存同步在保证数据一致性的同时,提供了接近本地缓存的性能表现。