分布式锁~

分布式锁

分布式锁是在分布式系统中用于协调多个节点之间对共享资源的访问的一种机制。个人认为实现分布式锁,需要一个中间件例如数据库,redis等等这样的存储锁即可实现分布式锁。

分布式锁实现方案

  1. 基于数据库(唯一索引)

  2. 基于内存(redis,memcache)

  3. zookeeper

数据库

使用数据库的事务特性来实现分布式锁。

通过在数据库中创建一个表,将锁状态存储在表的行中,使用数据库的事务来确保对该行的操作是原子的。当一个节点想要获取锁时,尝试插入一行记录,如果插入成功则获取到锁,否则表示锁已被其他节点持有。

创建数据库表用于存储锁的状态

CREATE TABLE distributed_lock (lock_name VARCHAR(255) PRIMARY KEY,is_locked BOOLEAN NOT NULL DEFAULT FALSE
);

Java代码实现获取和释放分布式锁

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class DistributedLock {private static final String JDBC_URL = "jdbc:mysql://localhost:3306/your_database";private static final String JDBC_USER = "your_username";private static final String JDBC_PASSWORD = "your_password";private String lockName;private Connection connection;public DistributedLock(String lockName) {this.lockName = lockName;try {this.connection = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);} catch (SQLException e) {throw new RuntimeException("Failed to initialize database connection", e);}}public boolean acquireLock() {try {// Start a transactionconnection.setAutoCommit(false);// Try to insert a new lock recordtry (PreparedStatement insertStatement = connection.prepareStatement("INSERT INTO distributed_lock (lock_name, is_locked) VALUES (?, TRUE)")) {insertStatement.setString(1, lockName);int affectedRows = insertStatement.executeUpdate();// If affectedRows is 1, the lock is acquiredif (affectedRows == 1) {connection.commit();return true;}}// If a lock record already exists, it means the lock is held by another processconnection.rollback();return false;} catch (SQLException e) {try {connection.rollback();} catch (SQLException rollbackException) {// Handle rollback exception}throw new RuntimeException("Error while acquiring lock", e);} finally {try {connection.setAutoCommit(true);} catch (SQLException e) {// Handle setAutoCommit exception}}}public void releaseLock() {try (PreparedStatement deleteStatement = connection.prepareStatement("DELETE FROM distributed_lock WHERE lock_name = ?")) {deleteStatement.setString(1, lockName);deleteStatement.executeUpdate();} catch (SQLException e) {throw new RuntimeException("Error while releasing lock", e);}}public void closeConnection() {try {if (connection != null && !connection.isClosed()) {connection.close();}} catch (SQLException e) {// Handle close connection exception}}
}

基于缓存

这里主要讲基于Redis的分布式锁。

setNX + Lua脚本

在Redis中,你可以使用Lua脚本将SETNX和EXPIRE两个操作打包在一起,从而实现原子性。

local key = KEYS[1]
local value = ARGV[1]
local ttl = ARGV[2]local lockSet = redis.call('setnx', key, value)
if lockSet == 1 thenredis.call('expire', key, ttl)
endreturn lockSet
  1. 尝试使用SETNX命令设置一个锁。如果锁已经存在,那么SETNX命令会返回0,如果锁不存在,那么SETNX命令会返回1,并且设置锁的值为value
  2. 如果上一步设置锁成功(即SETNX命令返回1),那么使用EXPIRE命令设置锁的过期时间。过期时间是ttl
  3. 最后,返回SETNX命令的结果。如果结果为1,那么表示成功获取到了锁,如果结果为0,那么表示获取锁失败。

客户端调用脚本:

EVAL <lua_script> 1 lock_key lock_value lock_ttl

Redisson + RLock可重入锁

Redisson是一个分布式协调Redis客服端,实现了大部分java环境下分布式对象。

在这里插入图片描述

代码实现:

    Config config = new Config();config.useSingleServer().setAddress("redis://ip:6378").setPassword("root");Redisson redisson = Redisson.create(config);// 使用redisson自带的分布式锁RLock redisLock = redissonClient.getLock("junfeng");if (!redisLock.tryLock()) {return Result.fail("禁止重复参与!");}try {IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId); } finally {redisLock.unlock();}

redissonLock 比setnx有哪些优势

  • 实现了可重入
  • 锁续约机制
  • 实现多节点保存同一把锁,防止主从不一致问题

基于ZooKeeper

  • 使用ZooKeeper分布式协调服务。
  • 利用ZooKeeper的顺序临时节点(Sequential Ephemeral Node)创建有序节点,确保节点顺序代表获取锁的顺序。
  • 最小的节点代表获取了锁,其他节点监听前一个节点的删除事件。

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

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

相关文章

【QT系列教程】之二创建项目和helloworld案例

文章目录 一、QT创建项目1.1、创建项目1.2、选择创建项目属性1.3、选择路径和项目名称1.4、选择构建项目类型1.5、布局方式1.6、翻译文件&#xff0c;根据自己需求选择1.7、选择套件1.8、项目管理&#xff0c;自行配置1.9、配置完成&#xff0c;系统自动更新配置 二、QT界面介绍…

wpf devexpress 自定义统计

总计统计和分组统计包含预定义总计函数。这些函数允许你计算如下&#xff1a; 数据列的数量&#xff08;Count&#xff09; 最大和最小值(Max和Min) 总计和平均值&#xff08;Sum和Average&#xff09; 处理GridControl.CustomSummary 事件或者使用 GridControl.CustomSumm…

51单片机+DS1302设计一个电子钟(LCD1602显示时间)

一、前言 电子钟是一种能够准确显示时间的设备&#xff0c;广泛应用于家庭、办公场所和公共场所&#xff0c;为人们提供了方便和准确的时间信息。本项目设计一个基于51单片机的电子钟&#xff0c;使用DS1302作为RTC时钟芯片&#xff0c;LCD1602作为显示屏&#xff0c;并通过串…

torch_cluster、torch_scatter、torch_sparse三个包的安装

涉及到下面几个包安装的时候经常会出现问题&#xff0c;这里我使用先下载然后再安装的办法&#xff1a; pip install torch_cluster pip install torch_scatter pip install torch_sparse 1、选择你对应的torch版本&#xff1a;https://data.pyg.org/whl/ 2、点进去然后&…

网络安全-学习手册

前言 前几天发布了一篇 网络安全&#xff08;黑客&#xff09;自学 没想到收到了许多人的私信想要学习网安黑客技术&#xff01;却不知道从哪里开始学起&#xff01;怎么学 今天给大家分享一下&#xff0c;很多人上来就说想学习黑客&#xff0c;但是连方向都没搞清楚就开始学习…

C#检查服务状态,以及进行服务启停

1. linux环境 linux环境通过执行bash命令直接执行&#xff1a; public string RunCmdLinux(string cmd){var proc new Process();System.Console.Write($"Run Linux cmd > [{cmd}] START!");proc.StartInfo.CreateNoWindow true;proc.StartInfo.FileName &…

git clone:SSL: no alternative certificate subject name matches target host name

git clone 时的常见错误&#xff1a; fatal: unable to access ‘https://ip_or_domain/xx/xx.git/’: SSL: no alternative certificate subject name matches target host name ‘ip_or_domain’ 解决办法&#xff1a; disable ssl verify git config --global http.sslVe…

Redis分布式锁(中)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 我们在不久前介绍了Spr…

JavaEE初阶(18)(JVM简介:发展史,运行流程、类加载:类加载的基本流程,双亲委派模型、垃圾回收相关:死亡对象的判断算法,垃圾回收算法,垃圾收集器)

接上次博客&#xff1a;初阶JavaEE&#xff08;17&#xff09;Linux 基本使用和 web 程序部署-CSDN博客 目录 JVM 简介 JVM 发展史 JVM 运行流程 JVM的内存区域划分 JVM 执行流程 堆 堆的作用 JVM参数设置 堆的组成 垃圾回收 堆内存管理 类加载 类加载的基本流…

Flink(五)【DataStream 转换算子(上)】

前言 这节注定是一个大的章节&#xff0c;我预估一下得两三天&#xff0c;涉及到的一些东西不懂就重新学&#xff0c;比如 Lambda 表达式&#xff0c;我只知道 Scala 中很方便&#xff0c;但在 Java 中有点发怵了&#xff1b;一个接口能不能 new 来构造对象? 答案是可以的&…

Vue模板语法

模板语法有两大类&#xff1a; 1.插值语法 2.指令语法 让我为大家介绍一下吧&#xff01; 一、插值语法 功能:用于解析标签体内容。 写法: {{xxx}}&#xff0c;xxx是js表达式&#xff0c;且可以直接读取到data中的所有属性。 举个例子&#xff1a; <!DOCTYPE html> &l…

idea maven 构建本地jar包及pom文件

1、设置模块build 本地输出路径 <build><defaultGoal>compile</defaultGoal><resources><resource><directory>${basedir}/src/main/resources</directory><includes><include>**/**</include></includes>…

腾讯云服务器可用区是什么意思?

腾讯云服务器可用区是什么意思&#xff1f;云服务器可用区如何选择&#xff1f;可用区是指在同一个地域内电力和网络相互独立的区域&#xff0c;可用区可以做到故障隔离&#xff0c;所以可用区存在的意义在于构建高可用、高容灾应用&#xff0c;将应用部署在不同可用区内&#…

ChatkBQA:一个基于大语言模型的知识库问题生成-检索框架11.13

ChatkBQA&#xff1a;一个基于大语言模型的知识库问题生成-检索框架 摘要1 引言3 准备工作4 方法4.1 ChatKBQA概述4.2 在LLMS上进行高效微调4.3 用微调LLMS生成逻辑形式4.4 实体和关系的非监督检索4.5 可解释查询执行 摘要 基于知识的问答&#xff08;KBQA&#xff09;旨在从大…

Windows Server 2012 R2系统服务器远程桌面服务多用户登录配置分享

Windows Server 2012系统在没有安装远程多界面的情况下&#xff0c;最多只能同时运行2个远程桌面&#xff0c;如果是有多个技术员、合伙人同时操作或是像游戏开发需要用到多界面&#xff0c;但是没有安装就很不方便&#xff0c;今天飞飞来和你们分享Windows server 2012R2系统远…

C++ opencv基本用法【学习笔记(九)】

这篇博客为修改过后的转载&#xff0c;因为没有转载链接&#xff0c;所以选了原创 文章目录 一、vs code 结合Cmake debug1.1 配置tasks.json1.2 配置launch.json 二、图片、视频、摄像头读取显示2.1 读取图片并显示2.2 读取视频文件并显示2.3 读取摄像头并写入文件 三、图片基…

通过注释来埋点

目录 开始 插件编写 功能一 功能二 功能三 合并功能 运行代码 总结 这篇文章主要讲如何根据注释&#xff0c;通过babel插件自动地&#xff0c;给相应函数插入埋点代码&#xff0c;在实现埋点逻辑和业务逻辑分离的基础上&#xff0c;配置更加灵活 这篇文章想要达到的效…

2023最受推荐的五款项目管理工具

1、进度猫 进度猫是国内一款轻量级项目管理工具&#xff0c;适用于实时协作的团队。 以甘特图为向导&#xff0c;基于任务清单todolist&#xff0c;支持多用户协作&#xff1b; 甘特图显示具体任务清单、时间和任务的进度&#xff1b; 对未完成任务、已完成任务进行分类管…

Vue3源码reactive和readonly对象嵌套转换,及实现shallowReadonly

前言 官方文档中对reactive的描述&#xff1a; 响应式转换是“深层”的&#xff1a;它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性&#xff0c;同时保持响应性。 官方文档中对readonly的描述: 只读代理是深层的&#xff1a;对任何嵌套属性的访问都将是…

深入了解域名与SSL证书的关系

在如今数字化的世界里&#xff0c;网络安全成为我们关注的重要议题之一。为了确保数据在网络上传输的安全性&#xff0c;我们通常会采取各种安全措施&#xff0c;其中最常用的就是SSL证书。然而&#xff0c;很多人并不了解SSL证书是如何与域名相互关联的。 首先&#xff0c;我…