高并发下的分布式锁-mysql篇

2021-03-13  本文已影响0人  知名乐天

前言

不管是在面试中,还是在平时的工作中,高并发永远是衡量一个web工作者能力的重要场景。本篇幅我们主要是来讨论在高并发环境下我们应该如何实现分布式锁。
实现分布式锁的方式有比较多,这里主要考虑如何使用mysql实现分布式锁。

Mysql实现锁的方法

第一种,使用mysql唯一索引来实现:

针对这种实现,我们只需要新建一张表,专门用来处理分布式任务,比如新建一张 task的表,里面的唯一索引为 task_name 。

运行流程如下:当多个副本同时要抢占一个任务的锁的时候,就执行一个插入语句(这几个副本的task_name都是一致的),所以,当有一个副本之行插入成功后,后续的其他插入则会由于唯一索引的问题,导致插入失败。我们可以根据插入的影响条数为0 或者是1 ,判断是否抢锁成功。最后抢锁成功的副本,在任务执行结束之后,将该条记录删除,即把锁删除掉。

CREATE TABLE `tests`.`task`  (
  `task-name` varchar(255) NULL,
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `ctime` timestamp(0) NULL,
  `mtime` timestamp(0) NULL ON UPDATE CURRENT_TIMESTAMP(0),
  PRIMARY KEY (`id`),
  INDEX `uniq_idx_task_name`(`task-name`)
);

// 副本1执行:
INSERT INTO `tests`.`task`(`task-name`,  `ctime`, `mtime`) VALUES ('demo1', 1, NULL, NULL);

// 副本2同时执行
INSERT INTO `tests`.`task`(`task-name`, `ctime`, `mtime`) VALUES ('demo1', 1, NULL, NULL);

// 以上只会有一个副本执行成功,另一个副本会直接失败

第二种,使用mysql的悲观锁

for update 和 for udpate no wait :

// 为了方便这里借用上上面的task表
// 起一个终端,连接上数据库,然后执行以下:
set autocommit = 0;
select * from task for update;
// 等待一段时间后再执行;
commit;

此时,另一个终端执行,可以发现,执行 select的话,可以直接返回,但是update的话会产生阻塞,直到之前的事务commit(看执行时间就可以知道)


image.png
// 如果使用for update nowait;
// 副本1执行成功:
select * from task for update nowait;
// 副本2执行:
mysql> select * from task for update nowait;
ERROR 3572 (HY000): Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set

//值得注意的是,for update nowait 的话,如果你执行 update 操作的话,仍然会阻塞在那里。

第三种,使用乐观锁

结语

以上就是mysql锁的三种方式,不过说实话,mysql的性能确实在高并发环境下,不值得期待,但是多了解下这种知识,也算是扩宽下自己的解决问题的思路吧。
共勉

上一篇 下一篇

猜你喜欢

热点阅读