天天看點

鎖系列三:優雅的通過資料庫行鎖代替Redis實作分布式鎖1.背景前提2.使用方式3.行鎖、表鎖驗證

1.背景前提

当系统有一个时间较长的同步任务执行时,不能有其他线程重复去执行这个任务,因此需要用到锁,由于是集群应用,所以只能是分布式锁。

分布式锁比较常见的方式都是借助一个中间件实现的,比如zookeeper锁,redis锁。但是这样的话会额外映入一个组件,并不是很划算。一般系统会用到redis,所以使用redis锁的会比较常见,但是redis并非完全可靠,所以也不是特别好。

所以这里使用数据库(mysql)实现一种基于行锁的简单优雅的实现方式。

2.使用方式

假如id=1的这条数据需要进行一个同步的任务,且status=3表示此时有同步任务正在进行,其他任务应该被阻塞。可以使用下面的sql语句,只需要判断是否修改成功(返回的修改条数>=1即为成功)。

由于该操作是原子性的,加上数据库本身的函所支持。此时只会有一个线程能够修改成功,当他修改成功之后,其他线程修改的时候发现where条件不满足,则不会修改成功,也就不会进入后面的逻辑了。

3.行锁、表锁验证

3.1建表

CREATE TABLE `users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  `status` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
           
INSERT INTO `users` (`name`, `sex`, `status`) VALUES ( 'lk', '男', 0);
INSERT INTO `users` (`name`, `sex`, `status`) VALUES ('lk1', '男', 0);
INSERT INTO `users` (`name`, `sex`, `status`) VALUES ('zs', '女', 0);
INSERT INTO `users` (`name`, `sex`, `status`) VALUES ('ls', '男', 0);
           

事务开启与关闭

-- 查看是否开启自动提交
select @@autocommit;
-- 1开启 0关闭
set autocommit = 0
           

想要进行下面的验证,先将自动提交事务关闭。(注意验证完毕后开启自动提交哦)

3.2表锁

如下图,开始事务但是不提交,此时将全表数据锁住了,修改任意一条数据都不能成功。

在不使用到索引的情况下,直接使用where条件,会触发表锁(应为只能扫全表才知道where的是那条记录)

鎖系列三:優雅的通過資料庫行鎖代替Redis實作分布式鎖1.背景前提2.使用方式3.行鎖、表鎖驗證

提交事务之后,立马就能修改了

鎖系列三:優雅的通過資料庫行鎖代替Redis實作分布式鎖1.背景前提2.使用方式3.行鎖、表鎖驗證

3.3行锁

按照图中开启事务,但是不提交,此时会将id=1的记录锁住,无法进行修改,但是其他的没有被锁住的记录,比如图中的id=2的记录,还是可以修改的。

当使用了索引的时候,可以直接定位到那一条具体的记录,此时就会触发行锁了。

鎖系列三:優雅的通過資料庫行鎖代替Redis實作分布式鎖1.背景前提2.使用方式3.行鎖、表鎖驗證

繼續閱讀