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

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

2. 基于mysql实现分布式锁

不管是jvm锁还是mysql锁,为了保证线程的并发安全,都提供了悲观独占排他锁。所以独占排他也是 分布式锁的基本要求。 可以利用唯一键索引不能重复插入的特点实现。设计表如下:

1. CREATE TABLE `db_lock` (
2.   `id` bigint(20) NOT NULL AUTO_INCREMENT,
3.   `lock_name` varchar(50) NOT NULL COMMENT '锁名',
4.   `class_name` varchar(100) DEFAULT NULL COMMENT '类名',
5.   `method_name` varchar(50) DEFAULT NULL COMMENT '方法名',
6.   `server_name` varchar(50) DEFAULT NULL COMMENT '服务器ip',
7.   `thread_name` varchar(50) DEFAULT NULL COMMENT '线程名',
8.   `create_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP 
9. 
10. COMMENT '获取锁时间',
11.   `desc` varchar(100) DEFAULT NULL COMMENT '描述',
12.   PRIMARY KEY (`id`),
13.   UNIQUE KEY `idx_unique` (`lock_name`)
14. ) ENGINE=InnoDB AUTO_INCREMENT=1332899824461455363 DEFAULT CHARSET=utf8;

Lock实体类:  

1. @Data
2. @AllArgsConstructor
3. @NoArgsConstructor
4. @TableName("db_lock")
5. 
6. public class Lock {
7.    private Long id;
8.    private String lockName;
9.    private String className;
10.    private String methodName;
11.    private String serverName;
12.    private String threadName;
13.    private Date createTime;
14.    private String desc;
15. }

LockMapper接口:

1. public interface LockMapper extends BaseMapper<Lock> {
2. }

2.1. 基本思路

synchronized关键字和ReetrantLock锁都是独占排他锁,即多个线程争抢一个资源时,同一时刻只有 一个线程可以抢占该资源,其他线程只能阻塞等待,直到占有资源的线程释放该资源。

  1. 线程同时获取锁(insert)
  2. 获取成功,执行业务逻辑,执行完成释放锁(delete)
  3. 其他线程等待重试

2.2. 代码实现

改造StockService:

1. @Service
2. 
3. public class StockService {
4.    @Autowired
5.    private StockMapper stockMapper;
6.    @Autowired
7.    private LockMapper lockMapper;
8.    /**
9.      * 数据库分布式锁
10.      */
11.    public void checkAndLock() {
12.        // 加锁
13.        Lock lock = new Lock(null, "lock", this.getClass().getName(), new
14. Date(), null);
15.        try {
16.            this.lockMapper.insert(lock);
17.        } catch (Exception ex) {
18.            // 获取锁失败,则重试
19.            try {
20.                 Thread.sleep(50);
21.                this.checkAndLock();
22.            } catch (InterruptedException e) {
23.                 e.printStackTrace();
24.            }
25.        }
26.        // 先查询库存是否充足
27.        Stock stock = this.stockMapper.selectById(1L);
28.        // 再减库存
29.        if (stock != null && stock.getCount() > 0){
30.             stock.setCount(stock.getCount() - 1);
31.            this.stockMapper.updateById(stock);
32.        }
33.        // 释放锁
34.        this.lockMapper.deleteById(lock.getId());
35.    }
36. }

加锁:  

1. // 加锁
2. Lock lock = new Lock(null, "lock", this.getClass().getName(), new Date(), null);
3. try {
4.    this.lockMapper.insert(lock);
5. } catch (Exception ex) {
6.    // 获取锁失败,则重试
7.    try {
8.         Thread.sleep(50);
9.        this.checkAndLock();
10.    } catch (InterruptedException e) {
11.         e.printStackTrace();
12.    }
13. }

解锁:

1. // 释放锁
2. this.lockMapper.deleteById(lock.getId());

使用Jmeter压力测试结果:

可以看到性能感人。mysql数据库库存余量为0,可以保证线程安全。

2.3. 缺陷及解决方案

1. 这把锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。

解决方案:给锁数据库 搭建主备

2. 这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁。

解决方案:只要做一个定时任务,每隔一定时间把数据库中的超时数据清理一遍。

3. 这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。

解决方案:记录获取锁的主机信息和线程信息,如果相同线程要获取锁,直接重入。

4. 受制于数据库性能,并发能力有限。

解决方案:无法解决。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
9月前
|
关系型数据库 MySQL 分布式数据库
《MySQL 简易速速上手小册》第6章:MySQL 复制和分布式数据库(2024 最新版)
《MySQL 简易速速上手小册》第6章:MySQL 复制和分布式数据库(2024 最新版)
483 2
|
9月前
|
NoSQL 关系型数据库 MySQL
分布式锁(redis/mysql)
分布式锁(redis/mysql)
223 1
|
6月前
|
缓存 NoSQL 关系型数据库
(八)漫谈分布式之缓存篇:唠唠老生常谈的MySQL与Redis数据一致性问题!
本文来聊一个跟实际工作挂钩的老生常谈的问题:分布式系统中的缓存一致性。
200 11
|
8月前
|
SQL 关系型数据库 MySQL
MySQL高可用架构设计:从主从复制到分布式集群
MySQL高可用性涉及主从复制、半同步复制和Group/InnoDB Cluster。主从复制通过二进制日志同步数据,保证故障时可切换。半同步复制确保事务在至少一个从服务器确认后才提交。Group Replication是多主复制,支持自动故障切换。InnoDB Cluster是8.0的集成解决方案,简化集群管理。使用这些技术能提升数据库的稳定性和可靠性。
695 2
|
7月前
|
SQL 负载均衡 关系型数据库
分布式篇问题之MySQL数据库主从复制问题如何解决
分布式篇问题之MySQL数据库主从复制问题如何解决
|
8月前
|
关系型数据库 MySQL 数据库
深入OceanBase分布式数据库:MySQL 模式下的 SQL 基本操作
深入OceanBase分布式数据库:MySQL 模式下的 SQL 基本操作
|
9月前
|
canal 消息中间件 关系型数据库
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
310 0
|
9月前
|
SQL 关系型数据库 MySQL
Flink CDC产品常见问题之读分布式mysql报连接超时如何解决
Flink CDC(Change Data Capture)是一个基于Apache Flink的实时数据变更捕获库,用于实现数据库的实时同步和变更流的处理;在本汇总中,我们组织了关于Flink CDC产品在实践中用户经常提出的问题及其解答,目的是辅助用户更好地理解和应用这一技术,优化实时数据处理流程。
|
9月前
|
设计模式 Java 关系型数据库
BAT等大厂年薪30W+面试清单:JVM\MySQL\设计模式\分布式\微服务
疫情影响下招聘名额缩减不少,但阿里、腾讯、抖音、快手等互联网公司却加快了人才招聘的节奏。这里根据自身的实际经历,整理了一份面试这些大厂的清单,希望能帮助到大家查漏补缺,攻克面试难关。
|
24天前
|
关系型数据库 MySQL 数据库连接
数据库连接工具连接mysql提示:“Host ‘172.23.0.1‘ is not allowed to connect to this MySQL server“
docker-compose部署mysql8服务后,连接时提示不允许连接问题解决