在处理并发删除缓存和更新数据库的场景时,锁机制的正确运用至关重要。以下是详细的运作原理和解决方案:
BEGIN TRANSACTION;
-- 1. 获取行锁(排他锁)
SELECT * FROM table WHERE id = xxx FOR UPDATE;
-- 2. 删除缓存
DELETE FROM cache WHERE key = 'xxx';
-- 3. 更新数据库
UPDATE table SET column = value WHERE id = xxx;
COMMIT;
特点: - 先获取数据库行锁,确保独占访问 - 适用于写多读少场景 - 可能造成锁等待和死锁
-- 1. 删除缓存
DELETE FROM cache WHERE key = 'xxx';
-- 2. 更新数据库(带版本检查)
UPDATE table SET column = value, version = version + 1
WHERE id = xxx AND version = old_version;
-- 3. 检查影响行数,如果为0则重试或报错
特点: - 基于版本号或时间戳 - 适用于读多写少场景 - 需要处理更新失败的情况
public void updateData(int id, Object newData) {
// 1. 先删除缓存
cache.delete(id);
// 2. 获取分布式锁(防止并发更新)
Lock lock = distributedLock.acquireLock("update_"+id);
try {
// 3. 再次检查缓存(可能已被其他线程填充)
if (cache.get(id) != null) {
cache.delete(id);
}
// 4. 更新数据库(带事务)
transactionTemplate.execute(status -> {
dao.update(id, newData);
return null;
});
} finally {
lock.unlock();
}
}
数据库 | 锁特性 |
---|---|
MySQL(InnoDB) | 行级锁、间隙锁、Next-Key锁 |
PostgreSQL | 行级锁、咨询锁 |
Oracle | 行级锁、多版本并发控制 |
SQL Server | 行级锁、键范围锁 |
通过合理运用这些锁机制,可以确保在高并发环境下缓存和数据库的数据一致性。