锁系列三:优雅的通过数据库行锁代替Redis实现分布式锁

本文介绍了如何利用MySQL的行锁机制实现分布式锁,避免引入额外的中间件如zookeeper或redis。通过设置特定的status字段,结合UPDATE SQL的原子性,确保只有一个线程能执行同步任务。同时,通过示例展示了表锁和行锁的验证过程,说明了在事务中如何控制锁的粒度。
摘要由CSDN通过智能技术生成

1.背景前提

当系统有一个时间较长的同步任务执行时,不能有其他线程重复去执行这个任务,因此需要用到锁,由于是集群应用,所以只能是分布式锁。
分布式锁比较常见的方式都是借助一个中间件实现的,比如zookeeper锁,redis锁。但是这样的话会额外映入一个组件,并不是很划算。一般系统会用到redis,所以使用redis锁的会比较常见,但是redis并非完全可靠,所以也不是特别好。
所以这里使用数据库(mysql)实现一种基于行锁的简单优雅的实现方式。

2.使用方式

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

UPDATE users SET status = 3 WHERE id = 1 AND status!=3

由于该操作是原子性的,加上数据库本身的函所支持。此时只会有一个线程能够修改成功,当他修改成功之后,其他线程修改的时候发现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的是那条记录)
在这里插入图片描述
提交事务之后,立马就能修改了
在这里插入图片描述

3.3行锁

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

当使用了索引的时候,可以直接定位到那一条具体的记录,此时就会触发行锁了。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是lk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值