上一篇文章我们介绍了什么是分布式锁和分布式锁的一些基本概念。这篇文章我们来讲解一下基于数据库如何实现分布式锁。

基于数据库实现分布式锁

        基于数据库实现分布式锁可以分为两种方式,分别是基于数据库表和基于数据库排他锁。

基于数据库表

        要实现分布式锁,最简单的方式可能就是直接创建一张锁表,然后通过操作该表中的数据来实现。当我们要锁住某个方法或者资源时,我们就在这张表中增加一条记录,想要释放锁的时候就删除这条记录。

        当我们想要锁住某个方法时,执行以下SQL语句:

insert into methodLock(method_name,desc) values ('method_name','desc');

        因为我们对method_name做了唯一性约束,这里如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,可以执行方法的具体内容。

        当方法执行完成后,想要释放锁时,可以执行以下SQL语句:

delete from methodLock where method_name = 'method_name';

        但是上面这种简单的实现存在以下四个问题:

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

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

        (3)这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁的动作;

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

        针对以上的问题,我们可以通过以下方式来进行解决:

        (1)可以使用数据库集群来代替单点数据库;

        (2)可以定义一个定时任务,每隔一定时间把数据库中的超时数据清理一遍来解决锁没有超时时间的问题;

        (3)可以使用while循环进行不断的insert尝试,直到成功,解决锁是非阻塞的问题;

        (4)可以在数据库中加入一个字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁时先查询数据库,看这个字段记录的是否是当前获取锁的主机信息和线程信息,如果是,那就直接进行锁的分配即可。

基于数据库排他锁

        除了可以通过增删操作数据表中的记录以外,还可以借助数据库自带的锁来实现分布式锁。

        基于MySQL的InnoDB引擎,可以使用以下方式来进行加锁操作:

public boolean lock(){connection.setAutoCommit(false);while(true){try{result = select * from methodLock where method_name = ... for update;if(result == null){return true;}}catch(Exception e){}sleep(1000);}return false;
}

        在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁(InnoDB引擎在加锁的时候,只有通过索引进行检索的时候才会使用行锁,否则会使用表锁。这里我们希望使用行锁,就要给method_name添加索引。这个索引一定要创建成唯一索引,否则会出现多个重载方法之间无法同时被访问的问题。重载方法的话建议把参数类型也加上)。当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁。

        我们可以认为获得排他锁的线程即可获得分布式锁,当获取到锁之后,可以执行方法的业务逻辑,执行完方法之后,再通过以下方式进行解锁:

public void unlock(){connection.commit();
}

        通过connection.commit()操作来释放锁,可以有效的解决上面提到的无法释放锁和非阻塞锁问题。for update语句会在执行成功之后立即返回,在执行失败时会一直处于阻塞状态,直到成功;使用这种方式,出现意外时数据库会自动将锁释放掉。但是这种方法还是无法直接解决掉数据库单点和锁不可重入问题。

       使用这种方法还会带来新的问题,虽然我们对method_name使用了唯一索引,并且显示使用for update来使用行锁。但是,MySQL会对查询进行优化,即使在条件中使用了索引字段,但是否使用索引来进行检索还是由MySQL通过判断不同执行计划的代价来决定。如果最终MySQL走了表锁而没有走行锁,那么这种方式就失效了;另一个问题是,如果我们使用排他锁来实现分布式锁,那么一个排他锁长时间不提交,就会占用数据库连接。一旦类似的连接变得多了,就可能把数据库连接池撑爆。

总结

        依赖数据库实现分布式锁有两种方法,一种是基于数据库表,一种是基于数据库的排他锁。直接借助数据库实现分布式锁容易理解,但是其实现上会有各种各样的问题,解决这些问题会使得方案变得复杂,并且操作数据库会带来一定的性能开销,行锁的使用也不想我们认为的那样可靠,尤其是表比较小的时候很可能不走索引导致使用表锁。

        这篇文章我们讲解了如何基于数据库实现分布式锁,大家有什么问题或者勘误可以在评论区留言,笔者看到都会回复的。

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

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

相关文章

智能检测护航电池产业:容量设备如何提升效率与安全?

电池容量是衡量其储能能力的重要指标,直接影响设备续航与使用寿命。电池容量检测设备通过模拟真实使用场景,精准测量电池的充放电性能,为电池生产、质检及回收环节提供关键数据支持,成为保障电池品质与安全的核心工具。 核心功能…

介绍一款免费MES、开源MES系统、MES源码

一、系统概述: 万界星空科技免费MES、开源MES、商业开源MES、市面上最好的开源MES、MES源代码、适合二开的开源MES。 1.万界星空开源MES制造执行系统的Java开源版本。 开源mes系统包括系统管理,车间基础数据管理,计划管理,物料控制…

构建高性能日志系统:QGroundControl日志模块深度解析

引言:日志系统的重要性 在无人机地面站系统中,日志记录是诊断问题、分析性能的关键基础设施。QGroundControl(QGC)作为领先的开源无人机地面站软件,其日志系统设计值得深入探讨。本文将揭示QGC日志系统的核心技术&…

k8s查看内存占用前十的20个pod服务,不包括job

在 Kubernetes 中,您可以使用 kubectl 命令结合一些工具来查看内存占用前十的 Pod 服务,并排除 Job 类型的 Pod。以下是一个示例命令,您可以在终端中运行: kubectl top pods --all-namespaces --no-headers | grep -v job | sort …

Spring Boot 集成 LangChain4j 示例

文章目录 概述一、DeepSeek API Key 获取二、Spring Boot 集成 LangChain4j 示例三、拓展建议 概述 LangChain4j 是 LangChain 在 Java 生态下的实现,它是一个开源库,帮助你更方便地在 Spring Boot 应用中集成大语言模型(如 OpenAI 的 GPT-4…

数据差异的iOS性能调试:设备日志导出和iOS文件管理

在复杂iOS项目中,尤其是集成多个第三方服务、使用混合数据源(本地远程缓存)的系统里,“数据不一致”类问题极具迷惑性。一方面,数据看似可用,逻辑层也没有明显错误;另一方面,用户层面…

二进制与生活:从数字世界到人生哲理

二进制与生活:从数字世界到人生哲理 最近重温《少年谢尔顿》,被剧中谢尔顿与二进制对话的场景深深打动。这让我思考:二进制这个看似冰冷的数字系统,其实与我们的生活有着千丝万缕的联系。今天,让我们一起走进二进制的世…

基于SMB协议的内网存活主机探测技术研究

一、 技术背景 SMB(Server Message Block)协议是Windows环境中广泛使用的网络文件共享协议,默认开放于445端口。由于其在Windows系统中的核心地位,SMB协议常被用作内网探测的重要切入点。本文系统介绍多种基于SMB的存活主机探测技术,帮助安全…

IDEA21中文乱码解决办法

我改了很多,可能也改了一些没用的 1.在VM options中添加-Dstdout.encodingUTF-8 -Dstderr.encodingUTF-8 2.IDEA 控制台输出设置为 UTF-8 打开 IDEA → File → Settings(或 CtrlAltS) 搜索 "Encoding" 设置 Project Encoding 和…

时序数据库概念及IoTDB特性详解

一、数据库管理系统概述 数据,如同空气般普遍存在于我们的数字生活中,每一次点击手机都可能产生并记录数据。这些数据被存储在数据库中,而数据库实质上是“数据的集合”。数据库管理系统(DBMS)则负责这些“数据容器”…

leetcode:263. 丑数(python3解法,数学相关算法题)

难度:简单 丑数 就是只包含质因数 2、3 和 5 的 正 整数。 给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false 。 示例 1: 输入:n 6 输出:true 解释&am…

RK3568笔记八十五:LVGL播放AVI视频

若该文为原创文章,转载请注明原文出处。 最近有个需求,需要播放视频,但使用的框架是LVGL显示,所以了解了下LVGL怎么实现播放视频。 目前了解到的方法有两种: 一、使用ffmpeg方式,此方法适用于大部分视频 二、使用opencv方式,此方法适用于大部分视频 三、使用woshin…

stm32使用定时器PWM

1、定时器TIM PSC-Prescaler-预分频器 CNT-Counter-计数器 ARR-Auto Reload Register-自动重装寄存器 RCR-Repetition Counter Register-重复计数器 1、时钟来源:晶振提供频率,时钟树这些才提供时钟 分频系数 计数 3、实例 上面展示了假设使用外部石英晶振提供32.76…

2.3 Windows Vcpkg+MSVC编译FFmpeg 4.4.1

一、vcpkg安装ffmpeg 4.4.1 vcpkg的使用可以参考之前的文章:vcpkg 使用 1.1 查看vcpkg中的ffmpeg版本 查看库的版本:vcpkg.io 1.2 vcpkg.json文件解析 创建vcpkg.json文件: {"builtin-baseline": "984f9232b2fe0eb94f…

docker -v 之后docker cp报错

问题 我现在在本地已经可以正确运行这个文本纠错接口了,使用了-v 挂载,,当我使用docker cp时,报错了Error response from daemon: unlinkat /app/pycorrector/.git/objects/pack/pack-xxxxxx.pack: device or resource busy&…

10人团队SolidWorks云桌面服务器怎么连接

在当今数字化设计领域,SolidWorks作为主流的三维CAD软件,对硬件性能要求较高。 对于10人团队共享使用场景,云桌面服务器方案能有效解决硬件成本高、协作效率低等问题,这需从硬件选型、网络架构、云桌面平台部署、软件授权管理及用…

从源码角度了解Elasticsaerch(分布式协调排序、深分页问题)

引文 Elasticsearch基于Lucene所以很多系统实现都在其中,所以可以先看看Lucene的实现: https://blog.csdn.net/qq_35040959/article/details/147931034 项目组件 不像Kafka这种顶级项目核心性能组件全自己实现,ELK中有很多引用至第三方开放库; 网络模型-Netty 网络模型多重…

共读AI新圣经-深度学习读书笔记01

提示:本文是我参加datawhale活动的读书笔记,这是第一章的阅读笔记 文章目录 前言一、深度学习能做什么?二、教学案例总结 前言 随着大数据和算力的大幅提升,基于数据学习的解决方案正取代基于人工设计的解决方案 提示&#xff1a…

Android项目资源字符串内容多语言对齐工具 Python

Android项目资源字符串内容多语言对齐工具: #!/usr/bin/env python3import re from dataclasses import dataclass, field from typing import Optional, Dict, List from pathlib import Path import tkinter as tk from tkinter import filedialog, messageboxda…