SpringBoot Redis分布式锁

maven依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.14</version>
</dependency>

 

帮助类 采用redis的setNX实现

  • SETNX(SET If Not Exists):当且仅当 Key 不存在时,则可以设置,否则不做任何动作。

 

package com.whq.test;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;import java.util.concurrent.TimeUnit;@Component
@Slf4j
public class DistributedLockHelper {private final static long LOCK_EXPIRE = 30 * 1000L;//单个业务持有锁的时间30s,防止死锁private final static long LOCK_TRY_INTERVAL = 30L;//默认30ms尝试一次private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;//默认尝试20s@Autowiredprivate StringRedisTemplate stringRedisTemplate;/*** 尝试获取全局锁** @param key 锁的名称* @return true 获取成功,false获取失败*/public boolean tryLock(String key) {return getLock(key, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE);}/*** 尝试获取全局锁** @param key    锁的名称* @param timeout 获取超时时间 单位ms* @return true 获取成功,false获取失败*/public boolean tryLock(String key, long timeout) {return getLock(key, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE);}/*** 尝试获取全局锁** @param key        锁的名称* @param timeout     获取锁的超时时间* @param tryInterval 多少毫秒尝试获取一次* @return true 获取成功,false获取失败*/public boolean tryLock(String key, long timeout, long tryInterval) {return getLock(key, timeout, tryInterval, LOCK_EXPIRE);}/*** 尝试获取全局锁** @param key           锁的名称* @param timeout        获取锁的超时时间* @param tryInterval    多少毫秒尝试获取一次* @param lockExpireTime 锁的过期* @return true 获取成功,false获取失败*/public boolean tryLock(String key, long timeout, long tryInterval, long lockExpireTime) {return getLock(key, timeout, tryInterval, lockExpireTime);}/*** 操作redis获取全局锁** @param key           锁的名称* @param timeout        获取的超时时间* @param tryInterval    多少ms尝试一次* @param lockExpireTime 获取成功后锁的过期时间* @return true 获取成功,false获取失败*/public boolean getLock(String key, long timeout, long tryInterval, long lockExpireTime) {try {if (StringUtils.isEmpty(key)) {return false;}long startTime = System.currentTimeMillis();while(true){if (!stringRedisTemplate.hasKey(key)) {ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();if(ops.setIfAbsent(key, "", lockExpireTime, TimeUnit.MILLISECONDS)) {return true;}} else {//存在锁log.debug("lock is exist!!!");}if (System.currentTimeMillis() - startTime > timeout) {//尝试超过了设定值之后直接跳出循环return false;}Thread.sleep(tryInterval);}} catch (InterruptedException e) {log.error(e.getMessage());return false;}}/*** 释放锁*/public void releaseLock(String key) {if (!StringUtils.isEmpty(key)) {stringRedisTemplate.delete(key);}}}

调用测试

 

@RestController
@SpringBootApplication
@Slf4j
public class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class, args);}@Autowiredprivate DistributedLockHelper distributedLockHandler;@RequestMapping("lock")public String lock(){String key="testlock";log.info("准备获取锁");if(distributedLockHandler.tryLock(key)){try {//为了演示锁的效果,这里睡眠5000毫秒log.info("已经获取到锁");Thread.sleep(5000);}catch (Exception e){e.printStackTrace();}distributedLockHandler.releaseLock(key);log.info("锁已释放");}return "hello world!";}
}

配置application.yml


server:port: 18081spring:redis:host: 10.0.197.189port: 6379

 

注意:测试时要采用两个浏览器,或者一个用ip、一个用localhost访问,否则浏览器会同时只能进行一个请求。

测试输出日志

 

2019-07-23 14:42:52 1997495 [http-nio-18081-exec-1] INFO  com.whq.test.TestApplication - 准备获取锁 
2019-07-23 14:42:52 1997507 [http-nio-18081-exec-1] INFO  com.whq.test.TestApplication - 已经获取到锁 
2019-07-23 14:42:53 1998452 [http-nio-18081-exec-3] INFO  com.whq.test.TestApplication - 准备获取锁 
2019-07-23 14:42:57 2002510 [http-nio-18081-exec-1] INFO  com.whq.test.TestApplication - 锁已释放 
2019-07-23 14:42:57 2002530 [http-nio-18081-exec-3] INFO  com.whq.test.TestApplication - 已经获取到锁 
2019-07-23 14:43:02 2007535 [http-nio-18081-exec-3] INFO  com.whq.test.TestApplication - 锁已释放 

 

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

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

相关文章

require与include的区别

引用文件的方法有两种&#xff1a;require 及 include。两种方式提供不同的使用弹性。require 的使用方法如 require("MyRequireFile.php"); 。这个函数通常放在 PHP 程序的最前面&#xff0c;PHP 程序在执行前&#xff0c;就会先读入 require 所指定引入的文件&…

java实现map和object互转

maven依赖 <dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.3</version> </dependency> 工具类 /*** 对象工具类* 王洪岐 20190726*/ public class ObjectUtil …

分享自己作为一个程序员的找工作经历

我叫杨磊&#xff0c;从2016年5月开始学了关于软件开发的道路上&#xff0c;我是报一颗火热的心。在学习中&#xff0c;不说是最好的&#xff0c;但我觉得自己一定是很积极的去学习。 从学了之后的&#xff0c;放假时间&#xff0c;我大多时间都是用在码代码&#xff0c;不断的…

mybatisplus坑 insert标签insert into select无参数问题

实际项目中发现 <insert id"xxx"> insert into xxxx select xxxx </insert> 会报错 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error updating database. Cause: …

前端学习(2392):关于路径中的@

import Vue from vue import VueRouter from vue-router // 表示src路径的别名 好处就是它不受当前文件路径影响 import Login from /views/login/index Vue.use(VueRouter)// 路由配置表 const routes [{path: /login,name: login,component: Login }] const router new Vue…

Java调用ElasticSearch 7.2.1 保存、统计、多字段分组聚合

目录 maven引用 配置 配置类 保存数据方法 参照官方的引用方式会报错 分组统计 查询后再统计 多字段分组聚合 maven引用 注意版本与es版本一致 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-…

cocos2d-x 2.2 创建项目

楼主用的是2.2版本号 曾经的版本号是要在vs中加入模版 建立项目 但新版本号更新后使用python建立项目 最好是python2.7以上 找到create_project.py文件所在路径 tools/project-creator/.. 打开cmd.exe 输入 cd /d D:cocosdx/....... 后面为create_project.py所在的路径…

Postgresql时间处理

目录 时间/日期操作符 日期/时间函数 EXTRACT函数 综合示例 时间/日期操作符 操作符例子结果date 2011-09-28 integer 7date 2011-10-05date 2011-09-18 interval 1 hourtimestamp 2011-09-18 01:00date 2011-09-18 time 02:00timestamp 2011-09-18 02:00interval 1 day…

jmap报错unknown CollectedHeap type : class sun.jvm.hotspot.gc_interface.CollectedHeap

jmap报错 [roothost-10-0-197-189 service]# jmap -heap 12139 Attaching to process ID 12139, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.191-b12using thread-local object allocation. Parallel GC with 8 thread(s)H…

topcoder SRM712 Div1 LR

题目&#xff1a; Problem Statement We have a cyclic array A of length n. For each valid i, element i-1 the left neighbor of element i. Additionally, element n-1 is the left neighbor of element 0. You are given two vector<long long>s s and t, each…

Spring Boot Quartz应用

目录 简单用法 配置cronSchedule的写法 简单用法 直接EnableScheduling后&#xff0c;方法上加上Scheduled(cron "0 */1 * * * * ")就行了。 此种方式需要写死时间、写死实现&#xff0c;生产环境不方便配置控制。 EnableScheduling SpringBootApplication publi…

2491 玉蟾宫

2491 玉蟾宫 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master 题目描述 Description有一天&#xff0c;小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫&#xff0c;玉蟾宫宫主蓝兔盛情地款待了它们&#xff0c;并赐予它们一片土地。 这片土地被分成N*M个格子&am…

linux根目录空间占满问题排查

df -h 看到/目录已满 切换到根目录后看各个目录空间占用 cd / du -h -x --max-depth1 [rootlocalhost usr]# du -h -x --max-depth160M ./bin42M ./sbin460M ./lib207M ./lib64204M ./share0 ./etc0 ./games36K ./include12M ./libexec0 ./local0 ./src983M . 依次找到过大…

hihocoder 1183 割点和割边

链接&#xff1a; http://hihocoder.com/problemset/problem/1183 代码&#xff1a; 1 #include <map>2 #include <set>3 #include <cmath>4 #include <queue>5 #include <stack>6 #include <cstdio>7 #include <string>8 #include …

ubuntu navicat删除目录破解如何保留配置信息

配置信息存储位置&#xff1a; ~/.navicat64/user.reg 这个文件跟windows注册表导出的文件一样 下面分析配置中对我们有用的信息 字体设置&#xff1a; [Software\\PremiumSoft\\NavicatPremium] 1566266955 #time1d556fc440497e6 "AlreadyShowNavicateV121WelcomeS…

前端学习(2398):回顾

# 一、项目初始化## 使用 Vue CLI 创建项目> 注意&#xff1a;不要使用 Git Bash 执行项目创建操作&#xff0c;使用 cmd 或者 powershell 之类的工具。> 如果你还没有安装 VueCLI&#xff0c;或者版本低于 4&#xff0c;请执行下面的命令安装或是升级&#xff1a; >…

ubuntu经常提示:检测到系统程序出现问题

sudo vi /etc/default/apport 修改值 enabled0

前端学习(2399):关于编辑代码编辑器

代码段使用 可以对对应的编辑器去设置代码段

React Native 一些事

ReactJS 是否准备好 有时候我们常常需要监听 ReactJS 的的加载情况。 比如说&#xff0c;当获取一条推送&#xff0c;应用还没有起来&#xff0c;通过点击推送启动应用后&#xff0c;而推送中包含一些我们感兴趣的字段需要处理&#xff0c;我们如果直接把这条通知发送给 ReactJ…