怎么在MySQL数据库中实现一个分布式锁
发表于:2024-10-25 作者:千家信息网编辑
千家信息网最后更新 2024年10月25日,这篇文章将为大家详细讲解有关怎么在MySQL数据库中实现一个分布式锁,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。建表CREATE TABLE `gl
千家信息网最后更新 2024年10月25日怎么在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安全错误
数据库的锁怎样保障安全
恐惧之间现实与服务器连接中断
cf服务器合并
编写内网穿透服务器
linux数据库放在
重庆长寿网上生鲜软件开发
vs如何连数据库
国产三维设计软件开发
网络安全与执法专业哪个学校有
2021智慧树数据库答案
北京网络安全大会主题曲
招标法软件开发属于什么
杭州览财网络技术有限公司
数据库 友情链接表设计
大同网络技术价格多少
ai语音交互软件开发
软件开发的单机游戏
数据库中size的默认大小
软件开发的国企
开发数据库时首要环节是什么
哪里可以学习网络技术培训
免费白嫖国外永久服务器
网络技术真的好吗
大话西游服务器架设
16岁学网络技术好吗
数据库建模工具mysql的使用
公安部网络安全监察网站
远程配置服务器防火墙规则
用网页进数据库连接
苏宁软件开发很苦吗
南京广播电视大学试卷数据库官网