分布式锁Lock4J 使用总结

Lok4j 简介

lock4j是一个分布式锁组件,其提供了多种不同的支持以满足不同性能和环境的需求。

立志打造一个简单但富有内涵的分布式锁组件。

特点

  • 简单易用,功能强大,扩展性强。
  • 支持redission,redisTemplate,zookeeper。可混用,支持扩展

Docker 安装Redis

请参考文章:Docker 安装Redis

Docker 安装ZooKeeper

请参考文章:Docker 安装Zookeeper

SpringBoot 集成Lock4j 

Lock4j 之Reids 版本

pom.xml 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>SpringBootCase</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>SpringBoot-Lock4J</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><mybatisplus-spring-boot-starter.version>3.4.3</mybatisplus-spring-boot-starter.version><mysql-spring-boot-starter.version>8.0.19</mysql-spring-boot-starter.version></properties><dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatisplus-spring-boot-starter.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql-spring-boot-starter.version}</version></dependency><!--添加开源分布式锁Lock4j--><!--若使用redisTemplate作为分布式锁底层,则需要引入--><dependency><groupId>com.baomidou</groupId><artifactId>lock4j-redis-template-spring-boot-starter</artifactId><version>2.2.4</version></dependency></dependencies></project>

application.yml 之Redis 配置

server:port: 8086
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.43.10:3306/bill?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=trueusername: rootpassword: 123456hikari:minimum-idle: 10maximum-pool-size: 20idle-timeout: 500000max-lifetime: 540000connection-timeout: 60000connection-test-query: select 1redis:database: 0host: 192.168.43.10port: 6379jedis:pool:max-active: 200max-wait: -1max-idle: 10min-idle: 0timeout: 6000mybatis-plus:mapper-locations: classpath:mapper/*.xmltype-aliases-package: cn.zzg.mybatisplus.entity

controller 使用Lock4j 注解,实现分布式锁功能

package cn.zzg.lock.controller;import com.baomidou.lock.annotation.Lock4j;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/lock4j")
public class Lock4JController {@GetMapping("/lockMethod")@Lock4j(keys = {"#key"}, acquireTimeout = 1000, expire = 10000)public String lockMethod(@RequestParam String key){try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}return new String(key);}}

Lock4j 之Redission版本

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>SpringBootCase</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>SpringBoot-Lock4JRedission</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!--若使用redisson作为分布式锁底层,则需要引入--><dependency><groupId>com.baomidou</groupId><artifactId>lock4j-redisson-spring-boot-starter</artifactId><version>2.2.4</version></dependency></dependencies></project>

application.yml 配置文件

server:port: 8089
spring:redis:database: 0host: 192.168.43.10port: 6379jedis:pool:max-active: 200max-wait: -1max-idle: 10min-idle: 0timeout: 6000

 controller 使用Lock4j 注解,实现分布式锁功能

package cn.zzg.lock4j.controller;import com.baomidou.lock.annotation.Lock4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/lock4j")
public class Lock4JController {@GetMapping("/lockMethod")@Lock4j(keys = {"#key"}, acquireTimeout = 1000, expire = 10000)public String lockMethod(@RequestParam String key){try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}return new String(key);}}

Lock4j 之ZooKeeper 版本

pom.xml 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>SpringBootCase</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>SpringBoot-Lock4jZookeeper</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!--添加开源分布式锁Lock4j--><!--若使用Zookeeper作为分布式锁底层,则需要引入--><dependency><groupId>com.baomidou</groupId><artifactId>lock4j-zookeeper-spring-boot-starter</artifactId><version>2.2.4</version></dependency></dependencies></project>

application.yml 之zookeeper配置

server:port: 8087
spring:coordinate:zookeeper:zkServers: 192.168.43.10:2181

controller 使用Lock4j 注解,实现分布式锁功能

package cn.zzg.lock.controller;import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.lock.executor.ZookeeperLockExecutor;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/lock4j")
public class Lock4JController {@GetMapping("/lockMethod")@Lock4j(keys = {"#key"}, acquireTimeout = 1000, expire = 10000, executor = ZookeeperLockExecutor.class)public String lockMethod(@RequestParam String key){try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}return new String(key);}}

Lock4J 注解详解

 Lock4J 高级使用

1、配置获取锁超时时间和锁过期时间。

lock4j:acquire-timeout: 3000 #默认值3s,可不设置expire: 30000 #默认值30s,可不设置primary-executor: com.baomidou.lock.executor.RedisTemplateLockExecutor #默认redisson>redisTemplate>zookeeper,可不设置lock-key-prefix: lock4j #锁key前缀, 默认值lock4j,可不设置

acquire-timeout /排队时长,超出这个时间退出队列,并抛出超时异常。
expire 锁过期时间 。 主要是防止死锁。默认30秒是为了兼容绝大部分场景。 

2、自定义执行器。

前提条件必须继承抽象类:com.baomidou.lock.executor.AbstractLockExecutor<T> 

ZooKeeper 版本执行器之ZookeeperLockExecutor

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.baomidou.lock.executor;import java.util.concurrent.TimeUnit;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class ZookeeperLockExecutor extends AbstractLockExecutor<InterProcessMutex> {private static final Logger log = LoggerFactory.getLogger(ZookeeperLockExecutor.class);private final CuratorFramework curatorFramework;public InterProcessMutex acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {if (!CuratorFrameworkState.STARTED.equals(this.curatorFramework.getState())) {log.warn("instance must be started before calling this method");return null;} else {String nodePath = "/curator/lock4j/%s";try {InterProcessMutex mutex = new InterProcessMutex(this.curatorFramework, String.format(nodePath, lockKey));boolean locked = mutex.acquire(acquireTimeout, TimeUnit.MILLISECONDS);return (InterProcessMutex)this.obtainLockInstance(locked, mutex);} catch (Exception var10) {return null;}}}public boolean releaseLock(String key, String value, InterProcessMutex lockInstance) {try {lockInstance.release();return true;} catch (Exception var5) {log.warn("zookeeper lock release error", var5);return false;}}public ZookeeperLockExecutor(final CuratorFramework curatorFramework) {this.curatorFramework = curatorFramework;}
}

Redis 版本执行器之RedisTemplateLockExecutor

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.baomidou.lock.executor;import java.util.Collections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;public class RedisTemplateLockExecutor extends AbstractLockExecutor<String> {private static final Logger log = LoggerFactory.getLogger(RedisTemplateLockExecutor.class);private static final RedisScript<String> SCRIPT_LOCK = new DefaultRedisScript("return redis.call('set',KEYS[1],ARGV[1],'NX','PX',ARGV[2])", String.class);private static final RedisScript<String> SCRIPT_UNLOCK = new DefaultRedisScript("if redis.call('get',KEYS[1]) == ARGV[1] then return tostring(redis.call('del', KEYS[1])==1) else return 'false' end", String.class);private static final String LOCK_SUCCESS = "OK";private final StringRedisTemplate redisTemplate;public String acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {String lock = (String)this.redisTemplate.execute(SCRIPT_LOCK, this.redisTemplate.getStringSerializer(), this.redisTemplate.getStringSerializer(), Collections.singletonList(lockKey), new Object[]{lockValue, String.valueOf(expire)});boolean locked = "OK".equals(lock);return (String)this.obtainLockInstance(locked, lock);}public boolean releaseLock(String key, String value, String lockInstance) {String releaseResult = (String)this.redisTemplate.execute(SCRIPT_UNLOCK, this.redisTemplate.getStringSerializer(), this.redisTemplate.getStringSerializer(), Collections.singletonList(key), new Object[]{value});return Boolean.parseBoolean(releaseResult);}public RedisTemplateLockExecutor(final StringRedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}
}

3、自定义Key生成器

前提条件必须实现:com.baomidou.lock.LockKeyBuilder 接口

默认Key生成器:DefaultLockKeyBuilder

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.baomidou.lock;import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;public class DefaultLockKeyBuilder implements LockKeyBuilder {private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();private static final ExpressionParser PARSER = new SpelExpressionParser();private BeanResolver beanResolver;public DefaultLockKeyBuilder(BeanFactory beanFactory) {this.beanResolver = new BeanFactoryResolver(beanFactory);}public String buildKey(MethodInvocation invocation, String[] definitionKeys) {Method method = invocation.getMethod();return definitionKeys.length <= 1 && "".equals(definitionKeys[0]) ? "" : this.getSpelDefinitionKey(definitionKeys, method, invocation.getArguments());}protected String getSpelDefinitionKey(String[] definitionKeys, Method method, Object[] parameterValues) {StandardEvaluationContext context = new MethodBasedEvaluationContext((Object)null, method, parameterValues, NAME_DISCOVERER);context.setBeanResolver(this.beanResolver);List<String> definitionKeyList = new ArrayList(definitionKeys.length);String[] var6 = definitionKeys;int var7 = definitionKeys.length;for(int var8 = 0; var8 < var7; ++var8) {String definitionKey = var6[var8];if (definitionKey != null && !definitionKey.isEmpty()) {String key = (String)PARSER.parseExpression(definitionKey).getValue(context, String.class);definitionKeyList.add(key);}}return StringUtils.collectionToDelimitedString(definitionKeyList, ".", "", "");}
}

4、自定义锁获取失败策略

前提条件必须实现:com.baomidou.lock.LockFailureStrategy 接口

默认失败策略:DefaultLockFailureStrategy

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.baomidou.lock;import com.baomidou.lock.exception.LockFailureException;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class DefaultLockFailureStrategy implements LockFailureStrategy {private static final Logger log = LoggerFactory.getLogger(DefaultLockFailureStrategy.class);protected static String DEFAULT_MESSAGE = "request failed,please retry it.";public DefaultLockFailureStrategy() {}public void onLockFailure(String key, Method method, Object[] arguments) {throw new LockFailureException(DEFAULT_MESSAGE);}
}

5、手动获取/释放锁

通用方法:

@Service
public class CommonService {@Autowiredprivate LockTemplate lockTemplate;public void commonLock(String bizId) {// 各种查询操作 不上锁// ...// 获取锁final LockInfo lockInfo = lockTemplate.lock(bizId, 30000L, 5000L, RedissonLockExecutor.class);if (null == lockInfo) {throw new RuntimeException("业务处理中,请稍后再试");}// 获取锁成功,处理业务try {System.out.println("执行普通方法 , 当前线程:" + Thread.currentThread().getName());} finally {//释放锁lockTemplate.releaseLock(lockInfo);}//结束}
}

参考资料

官网地址:Lock4J

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

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

相关文章

分布式【Zookeeper三大核心之数据节点ZNode】

ZooKeeper在分布式领域&#xff0c;能够帮助解决很多很多的分布式难题&#xff0c;但是底层却只是依赖于两个主要的组件&#xff1a;ZNode文件/数据存储系统和watch监听系统&#xff0c;另外还有一大模块&#xff0c;就是ACL系统。本节我们介绍下znode文件/数据存储系统。 一、…

【QT】自定义代理类

目录 1 我们为什么要使用自定义代理类&#xff1f; 2 自定义代理类的基本设计要求 3 自定义代理的功能 4 基于QSpinBox的自定义代理类 5 自定义代理类的使用 1 我们为什么要使用自定义代理类&#xff1f; 传统的模型-视图框架可以让我们实现逻辑展示相分离&#xff0c;我们…

【Spring Cloud Gateway】1、Spring Cloud Gateway网关服务搭建

1、什么是网关&#xff1f; API Gateway&#xff08;APIGW / API 网关&#xff09;&#xff0c;顾名思义&#xff0c;是系统对外的唯一入口。API 网关封装了系统内部架构&#xff0c;为每个客户端提供定制的 API。 近几年来移动应用与企业间互联需求的兴起。从以前单一的 Web …

344. 反转字符串

344. 反转字符串 题目链接&#xff1a;344. 反转字符串 思路&#xff1a;表示确实偷懒了&#xff0c;直接用自带方法解决的。 代码如下&#xff1a; class Solution { public:void reverseString(vector<char>& s) {reverse(s.begin(),s.end());} };

QA 这个职位在中国有前途么?转自知乎

QA 这个职位在中国有前途么&#xff1f; 体现在学校里&#xff0c;大家找工作的时候明显不愿意去做测试&#xff0c;更多的是愿意去做developer。 黄延胜 测试架构师 216 人赞同 对这个问题的回复有2个答案. 第一段来自于2011年, 第二段来自于2015年. 我没有删除第一段是为…

Spring见解 1.2 IOC

2.3.Spring的IOC解决程序耦合 2.3.1.创建工程 2.3.1.1.pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sc…

网络安全的概念、类型和重要性

什么是网络安全&#xff1f; 网络安全是指用于防止网络攻击或减轻其影响的任何技术、措施或做法。网络安全旨在保护个人和组织的系统、应用程序、计算设备、敏感数据和金融资产&#xff0c;使其免受简单而不堪其绕的计算机病毒、复杂而代价高昂的勒索软件攻击&#xff0c;以及…

Jvm垃圾收集器系列之ZGC的小知识(个人见解仅供参考)

学习内容&#xff1a; 问&#xff1a;什么是STW&#xff1f; 答&#xff1a;STW是StopTheWorld的缩写&#xff0c;指的是在Java的垃圾回收过程中&#xff0c;暂停所有的业务线程&#xff0c;导致业务系统暂停。问&#xff1a;ZGC的设计目标是什么&#xff1f; 答&#xff1a;Z…

Spring 七种事务传播性介绍

作者&#xff1a;vivo 互联网服务器团队 - Zhou Shaobin 本文主要介绍了Spring事务传播性的相关知识。 Spring中定义了7种事务传播性&#xff1a; PROPAGATION_REQUIRED PROPAGATION_SUPPORTS PROPAGATION_MANDATORY PROPAGATION_REQUIRES_NEW PROPAGATION_NOT_SUPPORTED…

八、QLayout 用户基本资料修改(Qt5 GUI系列)

目录 一、设计需求 二、实现代码 三、代码解析 四、总结 一、设计需求 在很多应用程序中会有用户注册或用户编辑信息等界面。本文就设计一个用户信息编辑界面。要求包含用户名、姓名、性别、部门、年龄、头像、个人说明等信息。 二、实现代码 #ifndef DIALOG_H #define D…

springboot中引入AOP切面编程

在Spring Boot 3.0中引入AOP的过程如下所示&#xff1a; 1、首先&#xff0c;确保已经添加了相关依赖。可以通过Maven或Gradle来管理项目的依赖。对于使用Maven构建的项目&#xff0c;需要将以下依赖添加到pom.xml文件中 <dependency><groupId>org.springframewo…

BERT(从理论到实践): Bidirectional Encoder Representations from Transformers【3】

这是本系列文章中的第3弹,请确保你已经读过并了解之前文章所讲的内容,因为对于已经解释过的概念或API,本文不会再赘述。 本文要利用BERT实现一个“垃圾邮件分类”的任务,这也是NLP中一个很常见的任务:Text Classification。我们的实验环境仍然是Python3+Tensorflow/Keras…

Kafka高级应用:如何配置处理MQ百万级消息队列?

在大数据时代&#xff0c;Apache Kafka作为一款高性能的分布式消息队列系统&#xff0c;广泛应用于处理大规模数据流。本文将深入探讨在Kafka环境中处理百万级消息队列的高级应用技巧。 本文&#xff0c;已收录于&#xff0c;我的技术网站 ddkk.com&#xff0c;有大厂完整面经…

2023年度全球重大关基安全事件 TOP 10 | FreeBuf 年度盘点

2023年&#xff0c;针对关键信息基础设施的网络攻击已经演变成为了一个全球性的问题&#xff0c;无论是中、美、俄等国际大国&#xff0c;还是诸多小国/地区&#xff0c;无论是经济发达还是落后&#xff0c;都无法保证绝对免疫关键基础设施的攻击。为了保障国家安全和社会稳定&…

Nestjs 微服务实战 - 动态微服务创建链接

所有的微服务都需要做服务治理 服务治理包括(配置中心、服务发现、注册服务等等),常见的包括 Java 的 Nacos,这里不关注与服务治理,只说明,如何用 nest 网关,并且在网关层动态实现微服务注入 nestjs 官网的案例明显是偏向于手动注册微服务的,例如: /** Model */ @M…

力扣-42.接雨水

题目&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组[0,1,0,2…

Windows PowerShell的安全目标——安全警报

Windows PowerShell的安全目标——安全警报 1. 保证Shell安全 ​ 自从2006年年底PowerShell发布以来&#xff0c;微软在安全和脚本方面并没有取得很好的名声。毕竟那个时候&#xff0c;**VBScript和Windows Script Host(WSH)**是两个最流行的病毒和恶意软件的载体&#xff0c…

springBoot集成RabbitMQ实现(直连模式\路由模式\广播模式\主题模式)的消息发送和接收

该项目介绍了springboot如何集成rabbitMQ消息中间件,实现(直连模式\路由模式\广播模式\主题模式)的消息发送和接收 pom依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId

Linux_CentOS_7.9_MySQL_5.7配置数据库服务开机自启动之简易记录

前言&#xff1a; 作为运维保障&#xff0c;都无法准确预估硬件宕机的突发阶段&#xff0c;其生产数据实时在产出&#xff0c;那作为dba数据库服务的其重要性、必要性就突显而出。这里拿虚拟机试验做个配置记录&#xff0c;便于大家学习参考。 # 如出现服务器重启后登入报错无…

redisson滑动时间窗应用场景

概述 前10分钟内累计3次验证失败后&#xff0c;增加图形验证码验证条件&#xff0c;前10分钟内累计6次验证失败后&#xff0c;系统自动锁定该账号15分钟&#xff0c;15分钟后自动解锁&#xff1b;方案 基于redisson&#xff08;zset&#xff09;滑动时间窗记录最近10分钟内该…