1,分布式锁
@Service
@RequiredArgsConstructor
public class CacheService {
private final RedisTemplate<String, Object> redisTemplate;
private final ProductRepository productRepository;
private final DistributedLockService lockService;
private static final String PRODUCT_CACHE_PREFIX = "product:";
private static final String PRODUCT_LOCK_PREFIX = "lock:product:";
private static final long DEFAULT_LOCK_WAIT_TIME = 1000; // 1秒
private static final long DEFAULT_LOCK_LEASE_TIME = 5000; // 5秒
/**
* 获取商品信息(带缓存)
*/
public Product getProduct(Long productId) {
String cacheKey = PRODUCT_CACHE_PREFIX + productId;
String lockKey = PRODUCT_LOCK_PREFIX + productId;
// 1. 先查缓存
Product product = (Product) redisTemplate.opsForValue().get(cacheKey);
if (product != null) {
return product;
}
// 2. 缓存不存在,加分布式锁查数据库
return lockService.executeWithLock(lockKey,
DEFAULT_LOCK_WAIT_TIME,
DEFAULT_LOCK_LEASE_TIME,
() -> {
// 双重检查,防止重复查询数据库
Product cachedProduct = (Product) redisTemplate.opsForValue().get(cacheKey);
if (cachedProduct != null) {
return cachedProduct;
}
// 查询数据库
Product dbProduct = productRepository.findById(productId)
.orElseThrow(() -> new RuntimeException("Product not found"));
// 写入缓存,设置过期时间
redisTemplate.opsForValue().set(
cacheKey,
dbProduct,
30, TimeUnit.MINUTES); // 30分钟过期
return dbProduct;
});
}
/**
* 更新商品信息(保证缓存与数据库一致性)
*/
public Product updateProduct(Product product) {
String lockKey = PRODUCT_LOCK_PREFIX + product.getId();
return lockService.executeWithLock(lockKey,
DEFAULT_LOCK_WAIT_TIME,
DEFAULT_LOCK_LEASE_TIME,
() -> {
// 1. 更新数据库
Product updatedProduct = productRepository.save(product);
// 2. 删除缓存
redisTemplate.delete(PRODUCT_CACHE_PREFIX + product.getId());
// 3. 可选的延迟双删(针对极端情况)
new Thread(() -> {
try {
Thread.sleep(500); // 延迟500ms
redisTemplate.delete(PRODUCT_CACHE_PREFIX + product.getId());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
return updatedProduct;
});
}
/**
* 带版本控制的更新(乐观锁)
*/
public Product updateProductWithVersion(Product product) {
String lockKey = PRODUCT_LOCK_PREFIX + product.getId();
return lockService.executeWithLock(lockKey,
DEFAULT_LOCK_WAIT_TIME,
DEFAULT_LOCK_LEASE_TIME,
() -> {
// 1. 先获取当前版本
Product existing = productRepository.findById(product.getId())
.orElseThrow(() -> new RuntimeException("Product not found"));
// 2. 检查版本
if (!existing.getVersion().equals(product.getVersion())) {
throw new RuntimeException("Optimistic lock failed");
}
// 3. 更新数据库
Product updatedProduct = productRepository.save(product);
// 4. 删除缓存
redisTemplate.delete(PRODUCT_CACHE_PREFIX + product.getId());
return updatedProduct;
});
}
}
2,基于消息队列的最终一致性
@Service
@RequiredArgsConstructor
public class MQConsistencyService {
private final RedisTemplate<String, Object> redisTemplate;
private final ProductRepository productRepository;
private final RabbitTemplate rabbitTemplate;
private static final String CACHE_UPDATE_QUEUE = "cache.update.queue";
/**
* 更新数据库并发送缓存更新消息
*/
public void updateProductWithMQ(Product product) {
// 1. 更新数据库
productRepository.save(product);
// 2. 发送消息到MQ
rabbitTemplate.convertAndSend(CACHE_UPDATE_QUEUE,
new CacheUpdateMessage(
product.getId(),
"DELETE"));
}
/**
* 消息处理器
*/
@RabbitListener(queues = CACHE_UPDATE_QUEUE)
public void handleCacheUpdate(CacheUpdateMessage message) {
try {
if ("DELETE".equals(message.getAction())) {
redisTemplate.delete("product:" + message.getProductId());
}
// 可以扩展其他操作
} catch (Exception e) {
// 加入重试逻辑
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class CacheUpdateMessage {
private Long productId;
private String action;
}
}