MySQL 某个表字段实现分布式锁
文章目录0.背景1. 实现原理2. 核心要点3. 完整使用流程4. 优缺点分析5. 适用场景6. 与其他方案的对比7. 总结参考文献0.背景比如使用 MySQL 的locked_at字段bigint unsigned时间戳来实现分布式锁或防止并发处理是一种基于数据库行锁 乐观锁的常见设计。它不依赖外部中间件如 Redis实现简单非常适合低并发、对性能要求不苛刻的后台任务。核心思想是获取锁就是尝试更新locked_at字段利用 MySQL 的原子更新特性保证同一时间只有一个线程/进程能更新成功。1. 实现原理假设有一张任务表jobs结构如下CREATETABLEjobs(idbigintNOTNULLAUTO_INCREMENT,statustinyintNOTNULLCOMMENT0待处理 1处理中 2已完成,locked_atbigintunsignedDEFAULTNULLCOMMENT锁定时间戳(毫秒)NULL表示未锁定,locked_byvarchar(100)DEFAULTNULLCOMMENT锁定者标识(IP/机器名/PID),retry_countintDEFAULT0,PRIMARYKEY(id),KEYidx_status_lock(status,locked_at));获取锁的 SQL关键操作-- 原子操作尝试锁定一条待处理的任务UPDATEjobsSETlocked_atUNIX_TIMESTAMP(NOW(3))*1000,-- 当前毫秒时间戳locked_byservice-a:pid12345,status1-- 可选更新状态WHEREstatus0-- 待处理AND(locked_atISNULL-- 从未被锁定ORlocked_atUNIX_TIMESTAMP(NOW(3))*1000-60000)-- 锁超时(60秒)LIMIT1;UPDATE语句在 MySQL 中具备行锁原子性当多个进程同时执行时只有一个能成功更新获取到锁。成功更新的行数 (rows affected) 为 1表示获取锁成功。释放锁的 SQL-- 只有当自己的锁才能释放UPDATEjobsSETlocked_atNULL,locked_byNULL,status0WHEREid123ANDlocked_byservice-a:pid12345;2. 核心要点原子性UPDATE ... WHERE是原子操作数据库行锁确保了并发安全。超时机制通过locked_at时间戳判断锁是否过期防止死锁。锁归属通过locked_by记录锁持有者确保只有加锁者能解锁避免误删。3. 完整使用流程typeJobLockerstruct{db*sql.DB}// TryLock 尝试获取锁返回是否成功及锁定的任务IDfunc(l*JobLocker)TryLock(lockerIDstring,timeoutMsint64)(jobIDint64,errerror){// 1. 尝试锁定result,err:l.db.Exec( UPDATE jobs SET locked_at ?, locked_by ?, status 1 WHERE status 0 AND (locked_at IS NULL OR locked_at ?) LIMIT 1 ,time.Now().UnixMilli(),lockerID,time.Now().UnixMilli()-timeoutMs)iferr!nil{return0,err}rowsAffected,_:result.RowsAffected()ifrowsAffected0{return0,nil// 没抢到锁}// 2. 查询被锁定的任务IDvaridint64errl.db.QueryRow( SELECT id FROM jobs WHERE locked_by ? AND locked_at ? ,lockerID,time.Now().UnixMilli()-5000).Scan(id)returnid,err}// Unlock 释放锁func(l*JobLocker)Unlock(jobIDint64,lockerIDstring)error{_,err:l.db.Exec( UPDATE jobs SET locked_at NULL, locked_by NULL, status 0 WHERE id ? AND locked_by ? ,jobID,lockerID)returnerr}4. 优缺点分析优点缺点实现简单无需引入额外组件性能瓶颈不适合高并发场景数据库压力大可靠性高基于 ACID 事务保证依赖时钟需要服务器时间准确易于调试锁状态可直接 SQL 查询清理负担需要定时任务清理过期锁事务友好可与其他操作组合连接池压力长任务占用数据库连接5. 适用场景分布式定时任务调度多实例环境下确保同一任务只被执行一次。消息消费幂等控制防止消息被重复消费。后台数据处理如数据归档、报表生成等低频操作。并发量较低的场景QPS 100。6. 与其他方案的对比方案优点缺点适用场景MySQL 乐观锁实现简单无外部依赖性能较低有单点风险低并发简单任务Redis 分布式锁高性能支持自动过期需要额外组件实现复杂高并发要求响应快ZooKeeper强一致性支持故障转移重量级维护成本高对一致性要求极高7. 总结使用locked_at字段实现 MySQL 分布式锁是工程中非常实用的技巧。它虽然不如 Redis 或 ZooKeeper 那样高性能但对于大多数内部后台管理系统、定时任务、低频并发控制场景是一种简单、可靠、低成本的解决方案。关键点是正确利用UPDATE ... WHERE的原子性并设计好超时和归属机制。参考文献《锁系列三优雅的通过数据库行锁代替Redis实现分布式锁》《详解分布式锁的三种实现方式MySQL vs Redis vs ZooKeeper》