​【五一创作】基于mysql关系型实现分布式锁(一)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: ​【五一创作】基于mysql关系型实现分布式锁

看完该文预计用时:15分钟

看之前应具体的技术栈:springboot mysql nginx(了解即可)

0.写在前面

在多线程高并发场景下,为了保证资源的线程安全问题,jdk为我们提供了synchronized关键字和

ReentrantLock可重入锁,但是它们只能保证一个jvm内的线程安全。在分布式集群、微服务、云原生横行的当下,如何保证不同进程、不同服务、不同机器的线程安全问题,jdk并没有给我们提供既有的解决方案。此时,我们就必须借助于相关技术手动实现了。目前主流的实现有三种方式:

1. 基于mysql关系型实现

2. 基于redis非关系型数据实现

3. 基于zookeeper实现

这篇文章主要讲解的是基于基于mysql关系型实现分布式锁

1. 从减库存聊起

库存在并发量较大情况下很容易发生超卖现象,一旦发生超卖现象,就会出现多成交了订单而发不了货的情况。

场景:

       商品S库存余量为5时,用户A和B同时来购买一个商品S,此时查询库存数都为5,库存充足则开始减库存:

用户A:update db_stock set stock = stock - 1 where id = 1

用户B:update db_stock set stock = stock - 1 where id = 1

并发情况下,更新后的结果可能是4,而实际的最终库存量应该是3才对

1.1. 环境准备

为了模拟具体场景我们需要准备开发环境

首先需要在mysql数据库中准备一张表:

1. CREATE TABLE `db_stock` (
2. `id` bigint(20) NOT NULL AUTO_INCREMENT,
3. `product_code` varchar(255) DEFAULT NULL COMMENT '商品编号',
4. `stock_code` varchar(255) DEFAULT NULL COMMENT '仓库编号',
5. `count` int(11) DEFAULT NULL COMMENT '库存量',
6. PRIMARY KEY (`id`)
7. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

表中数据如下:

创建分布式锁demo工程:

建立以下工具目录结构:

pom依赖文件:

1. 
2.     <dependencies>
3.         <dependency>
4.             <groupId>org.springframework.boot</groupId>
5.             <artifactId>spring-boot-starter-web</artifactId>
6.         </dependency>
7.         <dependency>
8.             <groupId>mysql</groupId>
9.             <artifactId>mysql-connector-java</artifactId>
10.             <version>5.1.46</version>
11.         </dependency>
12.         <dependency>
13.             <groupId>com.baomidou</groupId>
14.             <artifactId>mybatis-plus-boot-starter</artifactId>
15.             <version>3.4.0</version>
16.         </dependency>
17.         <dependency>
18.             <groupId>org.projectlombok</groupId>
19.             <artifactId>lombok</artifactId>
20.             <version>1.18.16</version>
21.         </dependency>
22.         <dependency>
23.             <groupId>org.springframework.boot</groupId>
24.             <artifactId>spring-boot-starter-data-redis</artifactId>
25.         </dependency>
26.         <dependency>
27.             <groupId>org.springframework.boot</groupId>
28.             <artifactId>spring-boot-devtools</artifactId>
29.         </dependency>
30.         <dependency>
31.             <groupId>org.springframework.boot</groupId>
32.             <artifactId>spring-boot-starter-test</artifactId>
33.             <scope>test</scope>
34.             <exclusions>
35.                 <exclusion>
36.                     <groupId>org.junit.vintage</groupId>
37.                     <artifactId>junit-vintage-engine</artifactId>
38.                 </exclusion>
39.             </exclusions>
40.         </dependency>
41.     </dependencies>
42.     <build>
43.         <plugins>
44.             <plugin>
45.                 <groupId>org.springframework.boot</groupId>
46.                 <artifactId>spring-boot-maven-plugin</artifactId>
47.             </plugin>
48.         </plugins>
49.     </build>
50. </project>

application.yml配置文件:

1. server:
2.   port: 6000
3. spring:
4.   datasource:
5.     driver-class-name: com.mysql.jdbc.Driver
6.     url: jdbc:mysql://172.16.116.100:3306/test
7.     username: root
8.     password: root

DistributedLockApplication启动类:

1. @SpringBootApplication
2. @MapperScan("com.atguigu.distributedlock.mapper")
3. 
4. public class DistributedLockApplication {
5.    public static void main(String[] args) {
6.         SpringApplication.run(DistributedLockApplication.class, args);
7.    }
8. }

Stock实体类:

1. @Data
2. @TableName("db_stock")
3. public class Stock {
4.   @TableId
5.   private Long id;
6.   private String productCode;
7.   private String stockCode;
8.   private Integer count;
9. }

StockMapper接口:

1. public interface StockMapper extends BaseMapper<Stock> {
2. }

 1.2. 简单实现减库存

接下来咱们代码实操一下

StockController:

1. @RestController
2. public class StockController {
3. @Autowired
4. private StockService stockService;
5. @GetMapping("check/lock")
6. public String checkAndLock(){
7. this.stockService.checkAndLock();
8. return "验库存并锁库存成功!";
9.     }
10. }

StockService:

1. @Service
2. public class StockService {
3. @Autowired
4. private StockMapper stockMapper;
5. 
6. public void checkAndLock() {
7. // 先查询库存是否充足
8. Stock stock = this.stockMapper.selectById(1L);
9. // 再减库存
10. if (stock != null && stock.getCount() > 0) {
11.             stock.setCount(stock.getCount() - 1);
12. this.stockMapper.updateById(stock);
13.         }
14.     }
15. }

测试:

查看数据库:

在浏览器中一个一个访问时,每访问一次,库存量减1,没有任何问题。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
关系型数据库 MySQL 分布式数据库
《MySQL 简易速速上手小册》第6章:MySQL 复制和分布式数据库(2024 最新版)
《MySQL 简易速速上手小册》第6章:MySQL 复制和分布式数据库(2024 最新版)
465 2
|
6月前
|
NoSQL 关系型数据库 MySQL
分布式锁(redis/mysql)
分布式锁(redis/mysql)
161 1
|
3月前
|
缓存 NoSQL 关系型数据库
(八)漫谈分布式之缓存篇:唠唠老生常谈的MySQL与Redis数据一致性问题!
本文来聊一个跟实际工作挂钩的老生常谈的问题:分布式系统中的缓存一致性。
153 11
|
5月前
|
SQL 关系型数据库 MySQL
MySQL高可用架构设计:从主从复制到分布式集群
MySQL高可用性涉及主从复制、半同步复制和Group/InnoDB Cluster。主从复制通过二进制日志同步数据,保证故障时可切换。半同步复制确保事务在至少一个从服务器确认后才提交。Group Replication是多主复制,支持自动故障切换。InnoDB Cluster是8.0的集成解决方案,简化集群管理。使用这些技术能提升数据库的稳定性和可靠性。
480 2
|
4月前
|
SQL 负载均衡 关系型数据库
分布式篇问题之MySQL数据库主从复制问题如何解决
分布式篇问题之MySQL数据库主从复制问题如何解决
|
5月前
|
关系型数据库 MySQL 数据库
深入OceanBase分布式数据库:MySQL 模式下的 SQL 基本操作
深入OceanBase分布式数据库:MySQL 模式下的 SQL 基本操作
|
6月前
|
canal 消息中间件 关系型数据库
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
266 0
|
6月前
|
SQL 关系型数据库 MySQL
Flink CDC产品常见问题之读分布式mysql报连接超时如何解决
Flink CDC(Change Data Capture)是一个基于Apache Flink的实时数据变更捕获库,用于实现数据库的实时同步和变更流的处理;在本汇总中,我们组织了关于Flink CDC产品在实践中用户经常提出的问题及其解答,目的是辅助用户更好地理解和应用这一技术,优化实时数据处理流程。
|
6月前
|
设计模式 Java 关系型数据库
BAT等大厂年薪30W+面试清单:JVM\MySQL\设计模式\分布式\微服务
疫情影响下招聘名额缩减不少,但阿里、腾讯、抖音、快手等互联网公司却加快了人才招聘的节奏。这里根据自身的实际经历,整理了一份面试这些大厂的清单,希望能帮助到大家查漏补缺,攻克面试难关。
|
1月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?