基于数据库实现分布式锁

news2024/9/30 21:24:27

分布式锁概述

前言

我们的系统都是分布式部署的,日常开发中,秒杀下单、抢购商品等等业务场景,为了防⽌库存超卖,都需要用到分布式锁。

分布式锁其实就是,控制分布式系统不同进程共同访问共享资源的一种锁的实现。如果不同的系统或同一个系统的不同主机之间共享了某个临界资源,往往需要互斥来防止彼此干扰,以保证一致性。

业界流行的分布式锁实现,一般有这3种方式:

  • 基于数据库实现的分布式锁。
  • 基于Redis实现的分布式锁。
  • 基于Zookeeper实现的分布式锁。

那下面我们就来聊聊基于数据库实现的分布式锁。

基于数据库的分布式锁

数据库悲观锁实现的分布式锁

可以使用select … for update 来实现分布式锁。我们自己的项目,分布式定时任务,就使用类似的实现方案,我给大家来展示个简单版的哈!

表结构如下:

CREATE TABLE `t_resource_lock` (
  `key_resource` varchar(45) COLLATE utf8_bin NOT NULL DEFAULT '资源主键',
  `status` char(1) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'S,F,P',
  `lock_flag` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '1是已经锁 0是未锁',
  `begin_time` datetime DEFAULT NULL COMMENT '开始时间',
  `end_time` datetime DEFAULT NULL COMMENT '结束时间',
  `client_ip` varchar(45) COLLATE utf8_bin NOT NULL DEFAULT '抢到锁的IP',
  `time` int(10) unsigned NOT NULL DEFAULT '60' COMMENT '方法生命周期内只允许一个结点获取一次锁,单位:分钟',
  PRIMARY KEY (`key_resource`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

加锁lock方法的伪代码如下:

@Transcational //一定要加事务
public boolean lock(String keyResource,int time){
   resourceLock = 'select * from t_resource_lock where key_resource ='#{keySource}' for update';
   
   try{
    if(resourceLock==null){
      //插入锁的数据
      resourceLock = new ResourceLock();
      resourceLock.setTime(time);
      resourceLock.setLockFlag(1);  //上锁
      resourceLock.setStatus(P); //处理中
      resourceLock.setBeginTime(new Date());
      int count = "insert into resourceLock"; 
      if(count==1){
         //获取锁成功
         return true;
      }
      return false;
   }
   }catch(Exception x){
      return false;
   }
   
   //没上锁并且锁已经超时,即可以获取锁成功
   if(resourceLock.getLockFlag=='0'&&'S'.equals(resourceLock.getstatus)
    && new Date()>=resourceLock.addDateTime(resourceLock.getBeginTime(,time)){
      resourceLock.setLockFlag(1);  //上锁
      resourceLock.setStatus(P); //处理中
      resourceLock.setBeginTime(new Date());
      //update resourceLock;
      return true;
   }else if(new Date()>=resourceLock.addDateTime(resourceLock.getBeginTime(,time)){
     //超时未正常执行结束,获取锁失败
     return false;
   }else{
     return false;
   } 
}

解锁unlock方法的伪代码如下:

public void unlock(String v,status){
      resourceLock.setLockFlag(0);  //解锁
      resourceLock.setStatus(status); S:表示成功,F表示失败
      //update resourceLock;
      return ;
}

整体流程:

try{
if(lock(keyResource,time)){ //加锁
   status = process();//你的业务逻辑处理。
 }
} finally{
    unlock(keyResource,status); //释放锁
}

其实这个悲观锁实现的分布式锁,整体的流程还是比较清晰的。就是先select … for update 锁住主键key_resource那个记录,如果为空,则可以插入一条记录,如果已有记录判断下状态和时间,是否已经超时。这里需要注意一下哈,必须要加事务哈。

2.2 数据库乐观锁实现的分布式锁

除了悲观锁,还可以用乐观锁实现分布式锁。乐观锁,顾名思义,就是很乐观,每次更新操作,都觉得不会存在并发冲突,只有更新失败后,才重试。它是基于CAS思想实现的。我以前的公司,扣减余额就是用这种方案。

搞个version字段,每次更新修改,都会自增加一,然后去更新余额时,把查出来的那个版本号,带上条件去更新,如果是上次那个版本号,就更新,如果不是,表示别人并发修改过了,就继续重试。

大概流程如下:

  • 查询版本号和余额。
select version,balance from account where user_id ='666';

假设查到版本号是oldVersion=1。
逻辑处理,判断余额。

if(balance<扣减金额){
   return}

left_balance = balance - 扣减金额;

进行扣减余额。

update account set balance = #{left_balance} ,version = version+1 where version 
= #{oldVersion} and balance>= #{left_balance} and user_id ='666';

大家可以看下这个流程图哈:
在这里插入图片描述
这种方式适合并发不高的场景,一般需要设置一下重试的次数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/348578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

xshell6运行报错:由于找不到mfc110u.dll、MSVCR110.dll无法继续执行代码

今天给大家分享一下我刚装完系统遇到得问题,由于新盟的罗建雨【胡巴】老师帮我给电脑加了固态,又重装了系统,因此电脑里面得所有软件需要重装,在我重装的过程中遇到了一个小问题给大家分享一下,如果大家以后遇到也方便解决。 问题: 安装Xshell时电脑系统报错:“由于找…

一、微服务架构介绍

目录 一、微服务架构介绍 二、出现和发展 三、传统开发模式和微服务的区别 四、微服务的具体特征 五、SOA和微服务的区别 1、SOA喜欢重用&#xff0c;微服务喜欢重写 2、SOA喜欢水平服务&#xff0c;微服务喜欢垂直服务 3、SOA喜欢自上而下&#xff0c;微服务喜欢自下…

为什么项目的时间跟踪管理很重要 ?

项目通常被分解为需要完成的任务&#xff0c;以实现项目目标。时间跟踪可以帮助你了解每项任务需要多长时间&#xff0c;从而使你更准确地估计未来的项目。 除此以外&#xff0c;跟踪项目时间还有以下令人难以置信的好处&#xff1a; 1、提高生产力 通过记录在每项任务上花…

项目经理为什么要做时间管理?

对于时间的管理&#xff0c;有人做不到&#xff0c;有人不知道&#xff0c;对每一个成功的人来说&#xff0c;时间管理是很重要的一环。 对于项目经理而言&#xff0c;由于项目经理每天要在项目上花费大量的时间&#xff0c;所以个人时间比较少&#xff0c;因此项目经理就需要安…

小半年被裁掉30多人,大厂“开猿节流”太狠了

今年9月&#xff0c;我前同事的小公司辞退了30多个程序员&#xff0c;当然包括做测试的他。 近3月过去了&#xff0c;大部分人都找不到合适工作。大家聊起时都在感慨这两年好多行业都不景气。 这次暂停了大部分业务&#xff0c;团队里最终只留下4个比较厉害的程序员合并到另外…

内网渗透(二十九)之Windows协议认证和密码抓取-Windows-2012R2之后抓取密码的方式和抓取密码的防范措施

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

Jdk19 动态编译 Java源码为 Class 文件

动态编译 Java 源码为 Class一.背景1.Jdk 版本2.需求二.Java 源码动态编译实现1.Maven 依赖2.源码包装类3.Java 文件对象封装类4.文件管理器封装类5.类加载器6.类编译器三.动态编译测试1.普通测试类2.接口实现类3.测试四.用动态编译 Class 替换 SpringBoot 的 Bean&#xff08;…

Hexo博客搭建部署GitHub

Hexo博客 Hexo是一个简洁的静态博客页面&#xff0c;使用markdown渲染文件&#xff0c;在本地生产静态文件后可以部署到GitHub上&#xff0c;这样不需要占用自己的域名和服务器&#xff0c;其实我在很早之前就换用了hexo&#xff0c;原来的博客在csdn&#xff0c;oceansec.blo…

康耐视智能相机Insight-选择型号方式

一&#xff1a;了解仿真中每种型号。 1.首先需要知道每种仿真代表的是多少万像素的相机&#xff0c;然后根据具体的分辨率去选择相应的型号&#xff0c;具体型号如下。 IS2000 30万相机 分辨率&#xff1a;640480 IS5000 30万相机 分辨率&#xff1a;640480 IS5001 130万相机 分…

[数据结构] 深入理解什么是跳表及其模拟实现

跳表定义优化实现基本框架定义跳表结点实现基础结构构造函数实现基本操作查找操作插入数据删除某结点打印跳表跳表与平衡搜索树和哈希表的对比定义 每相邻两个节点升高一层&#xff0c;增加一个指针&#xff0c;让指针指向下下个节点&#xff1b;上面每一层链表的节点个数&…

Xshell 7 连接云服务器的步骤和出现的错误

一、工具准备云服务器Xshell 7二、使用 Xshell 7 连接数据库三、新建会话属性后&#xff0c;没有自动弹出 SSH 用户名要求输入四、SSH 用户身份验证不能输入 Password五、Xshell 连接 centos 7 服务器 报错提示 “ssh服务拒绝了密码&#xff0c;请再试一次“&#xff0c;但是密…

信息安全工程

信息安全工程信息安全工程信息安全工程概述信息安全工程理论基础支撑信息安全工程的理论基础质量管理基本概念信息安全工程原理ISSE活动中支持认证和认可的活动信息安全工程监理模型信息安全工程能力评估SSE-CMM&#xff08;系统安全工程能力成熟度模型&#xff09;SSE-CMM 的安…

已解决SyntaxError: EOL while scanning string literal

已解决SyntaxError: EOL while scanning string literal 文章目录报错问题报错翻译报错原因解决方法联系博主免费帮忙解决报错报错问题 粉丝群里面的一个小伙伴遇到问题跑来私信我&#xff0c;想用eval函数转换字符串类型的字典&#xff0c;但是发生了报错&#xff08;当时他心…

全网最牛最全面的自动化平台从0到1地一步步搭建

来到新的公司有半年多了&#xff0c;由于业务和人员的极速扩张&#xff0c;整个局面处于百废待兴阶段&#xff0c;有太多方方面面的事情要做&#xff0c;前五个月基本上都是在给各式各样的需求进行支援&#xff0c;最近的两个月多月才比较固定做技术域的事情。所在组主要是做一…

前端学习第一阶段:第六章 HTML和CSS3

6-1 HTML5 01-HTML5CSS3提高导读 02-HTML5提高-新增语义化标签 03-HTML5-新增视频标签 04-HTML5新增音频标签 05-HTML5新增input表单 06-HTML5新增表单属性 6-2 CSS3 07-CSS3新增属性选择器&#xff08;上&#xff09; 08-CSS3新增属性选择器&#xff08;下&#xff09; 09-CSS…

C语言(指针,数组和函数)

目录 一.指针和数组 1.指向数组 2.数组下标和指针解引用的相等性 3.*和优先级问题 二..函数&#xff0c;数组和指针 1.声明数组形参 2.使用const保护地址数据 3.指针和多维数组 4.指向多维数组的指针 5.函数和多维数组 一.指针和数组 在前面的章节里面我们已经说过了…

Mr. Cappuccino的第39杯咖啡——Kubernetes之深入理解Pod

Kubernetes之深入理解PodPod相关概念Pod详细配置清单Pod核心配置Pod基本配置1. 创建yaml文件2. 创建namespace并根据yaml文件创建资源3. 查看namespace下的pod列表以及pod的详细信息Pod中多个容器的名称和端口号不能相同Pod镜像拉取策略Pod环境变量Pod端口相关设置Pod资源相关配…

echarts修改饼图,环形图的圆环宽度,大小

echarts修改环形图的圆环宽度&#xff0c;大小 环形图圆环的大小需要通过series-pie. radius属性来修改 radius 饼图的半径。 Array.<number|string>&#xff1a;数组的第一项是内半径&#xff0c;第二项是外半径。每一项遵从上述 number string 的描述。 把数组的第…

前端高频面试题—JavaScript篇(四)

&#x1f4bb; 前端高频面试题—JavaScript篇&#xff08;四&#xff09;&#x1f3e0;专栏&#xff1a;前端面试题 &#x1f440;个人主页&#xff1a;繁星学编程&#x1f341; &#x1f9d1;个人简介&#xff1a;一个不断提高自我的平凡人&#x1f680; &#x1f50a;分享方向…

150家半导体企业IPO最新进展(附企业名录)

前言 根据Omdia的数据显示&#xff0c;2022年全球在第一季度、第二季度、第三季度实现的半导体收入分别为1593亿美元、1581亿美元、1470亿美元&#xff0c;分别环比下降0.03%、1.9%、7.0%。 目前&#xff0c;半导体产业链经历了自2022上半年的欣欣向荣&#xff0c;到2022年下半…