怎么在MySQL数据库中实现一个分布式锁
发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,这篇文章将为大家详细讲解有关怎么在MySQL数据库中实现一个分布式锁,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。建表CREATE TABLE `gl
千家信息网最后更新 2025年02月01日怎么在MySQL数据库中实现一个分布式锁
这篇文章将为大家详细讲解有关怎么在MySQL数据库中实现一个分布式锁,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
建表
CREATE TABLE `globallocktable` ( `id` int(11) NOT NULL AUTO_INCREMENT, `lockKey` varchar(60) NOT NULL COMMENT '锁名称', `createTime` datetime NOT NULL COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `lockKey` (`lockKey`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='全局锁';
让别人使用的组件
@Componentpublic class GlobalLockComponent { @Resource GlobalLockTableDAO globalLockDAO; /** * 尝试获得锁,成功为true,失败为false */ public boolean tryLock(String key) { return GlobalLockUtil.tryLock(this.globalLockDAO, key); } /** * 如果已经有其他程序占用该锁,并且超过timeoutMs(毫秒)时间,就强制清除这个锁占用 * 即根据key先删除记录,再添加记录 */ public boolean tryLockWithClear(String key, Long timeoutMs) { return GlobalLockUtil.tryLockWithClear(this.globalLockDAO, key, timeoutMs); } /** * 释放锁,根据key删除记录 */ public void releasLock(String key) { GlobalLockUtil.releasLock(this.globalLockDAO, key); }}
锁对象定义如下
public class GlobalLockTable { private Integer id; private String lockKey; private Date createTime; // 省略get和set方法}GlobalLockTableDAO定义如下public interface GlobalLockTableDAO { int deleteByPrimaryKey(Integer id); int deleteByLockKey(String lockKey); GlobalLockTable selectByLockKey(String key); int insertSelectiveWithTest(GlobalLockTable record);}
具体加锁和解锁逻辑
public class GlobalLockUtil { private static Logger logger = LoggerFactory.getLogger(GlobalLockUtil.class); private static GlobalLockTable tryLockInternal(GlobalLockTableDAO lockDAO, String key) { GlobalLockTable insert = new GlobalLockTable(); insert.setCreateTime(new Date()); insert.setLockKey(key); // 注意的地方1 int count = lockDAO.insertSelectiveWithTest(insert); if (count == 0) { GlobalLockTable ready = lockDAO.selectByLockKey(key); logger.warn("can not lock the key: {}, {}, {}", insert.getLockKey(), ready.getCreateTime(), ready.getId()); return ready; } logger.info("yes got the lock by key: {}", insert.getId(), insert.getLockKey()); return null; } /** 超时清除锁占用,并重新加锁 **/ public static boolean tryLockWithClear(GlobalLockTableDAO lockDAO, String key, Long timeoutMs) { GlobalLockTable lock = tryLockInternal(lockDAO, key); if (lock == null) return true; if (System.currentTimeMillis() - lock.getCreateTime().getTime() <= timeoutMs) { logger.warn("sorry, can not get the key. : {}, {}, {}", key, lock.getId(), lock.getCreateTime()); return false; } logger.warn("the key already timeout wthin : {}, {}, will clear", key, timeoutMs); // 注意的地方2 int count = lockDAO.deleteByPrimaryKey(lock.getId()); if (count == 0) { logger.warn("sorry, the key already preemptived by others: {}, {}", lock.getId(), lock.getLockKey()); return false; } lock = tryLockInternal(lockDAO, key); return lock != null ? false : true; } /** 加锁 **/ public static boolean tryLock(GlobalLockTableDAO lockDAO, String key) { return tryLockInternal(lockDAO, key) == null ? true : false; } /** 解锁 **/ public static void releasLock(GlobalLockTableDAO lockDAO, String key) { lockDAO.deleteByLockKey(key); }}
这个工具类有2个特别有意思的地方,先看注意的地方2(上面代码中标识了)
1.为了避免锁长时间不释放,用Redis实现的话可以设置锁超时时间,超时自动释放(后面会写用Redis实现分布式锁)用MySQL实现的话可以先删除后添加。可以看到删除的时候使用id删的,不是用name删的。为啥呢?先自己想一下
因为如果是通过name删的话,有可能别人删了这个锁后,又通过name加了锁,还没到超时时间,结果你却根据name删除了。通过id删的话,当返回的id=0时,说明别人已经重新加锁了,你需要重新获取。
2.GlobalLockTable 对象dao层的其他方法都见名知意,来看一个这个方法。即代码中的注意点1
可以看到每次尝试加锁的时候,并不是先select,而是直接insertSelectiveWithTest,这样就少了一个查询时间,提高了效率
insertSelectiveWithTest的作用是当lockKey存在时不进行插入操作,返回0。当lockKey不存在时进行插入操作,返回1
insert into `globallocktable` (`id`, `lockKey`, `createTime` ) select #{id,jdbcType=INTEGER}, #{lockKey,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP} from dual where not exists (select 1 from globallocktable where lockKey = #{lockKey,jdbcType=VARCHAR})
使用
当我们想使用时,就只写业务逻辑就行了,非常方便
if (!globalLockComponent.tryLock(name)) { // 没有获取到锁返回 return;}try { // 这里写业务逻辑} catch (Exception e) {} finally { globalLockComponent.releasLock(name)
关于怎么在MySQL数据库中实现一个分布式锁就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
时间
地方
分布式
方法
逻辑
数据
数据库
中实
业务
代码
内容
对象
文章
时候
更多
知识
篇文章
尝试
不错
成功
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
服务器刻度怎么算
常用计算机网络安全技术
ssh网络安全协议
网络安全人才评价标准
中央网络安全信息小组会议
plsql选择数据库
快速java软件开发培训
连接数据库的为什么叫连接池
石景山区网络安全资质申请哪家好
退出服务器登录
北京龙商公社互联网科技发展
网络安全宣传周广元
逆水寒端游怎么选服务器
access数据库 页
数据库技术与应用段新昱答案
中学校园网络安全教学课件
内部服务器错误500
数据库应用系统开发技术研究
排队叫号系统软件开发
代理服务器 战网
it软件开发年度工作总结
网络技术服务费的发票税率
电子商务服务器硬件有哪些
网络安全维护难度大怎么解决
服务器电源效率分级 金
ios虚荣无法连接服务器
软件开发工程师的重要性
淮安专业软件开发价格多少
商洛管理软件开发
苹果php用什么软件开发