本文目录导读:

我来为您提供一个完整的Java缓存同步案例,涵盖常见的缓存同步策略。
基础缓存工具类
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheManager<K, V> {
private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
// 写入缓存
public void put(K key, V value) {
lock.writeLock().lock();
try {
cache.put(key, value);
System.out.println("缓存写入: " + key + " = " + value);
} finally {
lock.writeLock().unlock();
}
}
// 读取缓存
public V get(K key) {
lock.readLock().lock();
try {
return cache.get(key);
} finally {
lock.readLock().unlock();
}
}
// 删除缓存
public void remove(K key) {
lock.writeLock().lock();
try {
cache.remove(key);
System.out.println("缓存删除: " + key);
} finally {
lock.writeLock().unlock();
}
}
// 清空缓存
public void clear() {
lock.writeLock().lock();
try {
cache.clear();
System.out.println("缓存清空");
} finally {
lock.writeLock().unlock();
}
}
}
数据库与缓存同步服务
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class CacheSyncService {
@Autowired
private CacheManager<String, Object> cacheManager;
@Autowired
private UserRepository userRepository;
// 读取数据(先读缓存,再读数据库)
public User getUserById(String userId) {
// 1. 先查询缓存
User user = (User) cacheManager.get("user:" + userId);
if (user != null) {
System.out.println("从缓存获取用户: " + userId);
return user;
}
// 2. 缓存未命中,查询数据库
user = userRepository.findById(userId).orElse(null);
if (user != null) {
// 3. 将数据写入缓存
cacheManager.put("user:" + userId, user);
System.out.println("从数据库获取用户并写入缓存: " + userId);
}
return user;
}
// 更新数据(先更新数据库,再删除缓存)
@Transactional
public User updateUser(User user) {
// 1. 更新数据库
User updatedUser = userRepository.save(user);
System.out.println("数据库更新用户: " + user.getId());
// 2. 删除缓存(或更新缓存)
cacheManager.remove("user:" + user.getId());
System.out.println("删除用户缓存: " + user.getId());
return updatedUser;
}
// 删除数据(先删除数据库,再删除缓存)
@Transactional
public void deleteUser(String userId) {
// 1. 删除数据库
userRepository.deleteById(userId);
System.out.println("数据库删除用户: " + userId);
// 2. 删除缓存
cacheManager.remove("user:" + userId);
System.out.println("删除用户缓存: " + userId);
}
}
分布式缓存同步(使用Redis)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class DistributedCacheSyncService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ProductRepository productRepository;
private static final String PRODUCT_CACHE_KEY = "product:";
private static final long CACHE_TTL = 30; // 缓存过期时间(分钟)
// 缓存穿透保护:查询商品
public Product getProductById(String productId) {
String cacheKey = PRODUCT_CACHE_KEY + productId;
// 1. 查询缓存
Product product = (Product) redisTemplate.opsForValue().get(cacheKey);
if (product != null) {
System.out.println("从Redis缓存获取商品: " + productId);
return product;
}
// 2. 缓存未命中,加锁防止缓存击穿
synchronized (this) {
// 双重检查
product = (Product) redisTemplate.opsForValue().get(cacheKey);
if (product != null) {
return product;
}
// 查询数据库
product = productRepository.findById(productId).orElse(null);
if (product != null) {
// 设置缓存,带过期时间
redisTemplate.opsForValue().set(cacheKey, product, CACHE_TTL, TimeUnit.MINUTES);
System.out.println("从数据库获取商品并写入Redis: " + productId);
} else {
// 缓存空值,防止缓存穿透
redisTemplate.opsForValue().set(cacheKey, new EmptyProduct(), 5, TimeUnit.MINUTES);
System.out.println("商品不存在,缓存空值: " + productId);
}
}
return product;
}
// 更新商品(使用分布式锁)
@Transactional
public Product updateProduct(Product product) {
String lockKey = "lock:product:" + product.getId();
String cacheKey = PRODUCT_CACHE_KEY + product.getId();
// 获取分布式锁
boolean lockAcquired = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS);
if (!lockAcquired) {
throw new RuntimeException("获取分布式锁失败,请稍后重试");
}
try {
// 1. 更新数据库
Product updatedProduct = productRepository.save(product);
System.out.println("数据库更新商品: " + product.getId());
// 2. 删除缓存
redisTemplate.delete(cacheKey);
System.out.println("删除商品缓存: " + product.getId());
// 3. 发送消息通知其他节点
sendCacheInvalidationMessage(product.getId());
return updatedProduct;
} finally {
// 释放分布式锁
redisTemplate.delete(lockKey);
}
}
// 发送缓存失效消息
private void sendCacheInvalidationMessage(String productId) {
// 使用消息队列通知其他服务节点
System.out.println("发送缓存失效消息: " + productId);
}
// 消息队列监听器
public void handleCacheInvalidationMessage(String productId) {
String cacheKey = PRODUCT_CACHE_KEY + productId;
redisTemplate.delete(cacheKey);
System.out.println("接收消息并删除缓存: " + productId);
}
}
缓存同步监听器
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class CacheSyncListener {
@Autowired
private CacheManager<String, Object> cacheManager;
// 监听数据变更事件
@EventListener
public void handleDataChangeEvent(DataChangeEvent event) {
String cacheKey = event.getCacheKey();
switch (event.getChangeType()) {
case UPDATE:
case DELETE:
cacheManager.remove(cacheKey);
System.out.println("事件驱动缓存删除: " + cacheKey);
break;
case CREATE:
// 可选择立即加载或延迟加载
break;
}
}
}
// 数据变更事件
class DataChangeEvent {
private String cacheKey;
private ChangeType changeType;
public DataChangeEvent(String cacheKey, ChangeType changeType) {
this.cacheKey = cacheKey;
this.changeType = changeType;
}
public String getCacheKey() { return cacheKey; }
public ChangeType getChangeType() { return changeType; }
}
enum ChangeType {
CREATE, UPDATE, DELETE
}
定时缓存刷新
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Set;
@Component
public class CacheRefreshScheduler {
@Autowired
private CacheManager<String, Object> cacheManager;
@Autowired
private ProductRepository productRepository;
// 每小时刷新热门商品缓存
@Scheduled(cron = "0 0 * * * ?") // 每小时执行一次
public void refreshHotProductsCache() {
System.out.println("开始刷新热门商品缓存");
// 获取所有热门商品ID
Set<String> hotProductIds = getHotProductIds();
for (String productId : hotProductIds) {
String cacheKey = "hot:product:" + productId;
// 删除旧缓存
cacheManager.remove(cacheKey);
// 从数据库加载最新数据
Product product = productRepository.findById(productId).orElse(null);
if (product != null) {
cacheManager.put(cacheKey, product);
System.out.println("刷新商品缓存: " + productId);
}
}
}
private Set<String> getHotProductIds() {
// 模拟获取热点商品ID
return Set.of("001", "002", "003");
}
}
测试用例
public class CacheSyncTest {
public static void main(String[] args) {
CacheSyncService cacheService = new CacheSyncService();
// 模拟测试
System.out.println("=== 缓存同步测试 ===");
// 1. 第一次查询 - 缓存未命中
User user = cacheService.getUserById("001");
System.out.println("第一次查询结果: " + user);
// 2. 第二次查询 - 缓存命中
user = cacheService.getUserById("001");
System.out.println("第二次查询结果: " + user);
// 3. 更新数据
user.setName("新名称");
cacheService.updateUser(user);
// 4. 更新后查询 - 缓存已删除,重新加载
user = cacheService.getUserById("001");
System.out.println("更新后查询结果: " + user);
}
}
缓存同步关键策略
Cache-Aside Pattern (旁路缓存)
- 读:先读缓存 → 未命中读数据库 → 写入缓存
- 写:先更新数据库 → 删除缓存
缓存穿透防护
- 缓存空值
- 布隆过滤器
缓存击穿防护
- 互斥锁
- 双重检查
缓存雪崩防护
- 设置随机过期时间
- 多级缓存
这个案例展示了在实际项目中如何实现缓存同步,包括本地缓存、分布式缓存、事件驱动同步等常用模式。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播