基于数据库唯一索引 + 过期时间的分布式锁

多个服务抢同一行记录,谁插入成功谁拿锁;插入失败说明锁被占,再看它是否过期,过期就可以抢过来。

1. 建锁表

复制代码
CREATE TABLE distributed_lock (
  lock_key VARCHAR(64) PRIMARY KEY,
  owner VARCHAR(64) NOT NULL,
  expire_at DATETIME NOT NULL
);
  • lock_key:锁的名字,比如 order:123

  • owner:谁持有锁,比如 UUID

  • expire_at:过期时间,防止死锁

2. 加锁流程

先尝试插入:

复制代码
INSERT IGNORE INTO distributed_lock(lock_key, owner, expire_at)
VALUES ('order:123', 'uuid-1', NOW() + INTERVAL 30 SECOND);
  • 插入成功:拿到锁

  • 插入失败:说明已经有这行记录,锁被占了

然后尝试抢过期锁:

复制代码
UPDATE distributed_lock
SET owner = 'uuid-1', expire_at = NOW() + INTERVAL 30 SECOND
WHERE lock_key = 'order:123' AND expire_at < NOW();
  • 更新成功:说明旧锁过期了,你抢到了

  • 更新失败:说明锁还在有效期内,你没抢到

3. 释放锁

只删自己的锁,防止误删别人的:

复制代码
DELETE FROM distributed_lock
WHERE lock_key = 'order:123' AND owner = 'uuid-1';

4. 续期

业务还没执行完,但锁快过期了:

复制代码
UPDATE distributed_lock
SET expire_at = NOW() + INTERVAL 30 SECOND
WHERE lock_key = 'order:123' AND owner = 'uuid-1';

5. 关键点

  • lock_key 必须是主键或唯一索引,这是互斥的核心。

  • 必须有过期时间,否则服务挂了锁永远不释放。

  • 释放和续期都要带 owner,不能删别人的锁。

  • 必须读写主库,不能读从库,否则主从延迟会误判。

  • 适合并发不高的场景,高并发还是 Redis / ZooKeeper 更合适。

总结:

插入成功 = 拿锁;插入失败 = 看是否过期;过期就 UPDATE 抢锁;释放用 DELETE 带 owner 校验。

相关推荐
传奇开心果编程1 小时前
【ArkUI 练中学】第15课:UI 界面设计与实战
学习·ui·华为·harmonyos
传奇开心果编程3 小时前
【springboot基础语法学与练】第 1 课:从零开始
java·spring boot·后端·学习
扶风ff3 小时前
练题簿小程序:家庭在线练题,课后复习更简单
学习·小程序
传奇开心果编程3 小时前
【Flutter入门练中学】第2课:布局系统
学习·flutter·ui
彧azz3 小时前
Linux 网络编程学习总结
linux·网络·笔记·学习·面试
一尘之中4 小时前
指挥控制中心与指控系统:概念、应用、厂商与DDS技术全景
学习·架构·ai写作
一条破秋裤4 小时前
测试A学习顺序
学习
传奇开心果编程5 小时前
【Jetpack Compose基础语法学与练】第8课 rememberSaveable,页面旋转/系统重建保留状态
android·学习·ui·kotlin·android jetpack
迪丽热爱5 小时前
多媒体应用16-830(补)
学习