电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

SpringBoot中使用redis做分布式鎖的方法

瀏覽:4日期:2023-04-26 09:38:28

一.模擬問題

最近在公司遇到一個問題,掛號系統(tǒng)是做的集群,比如啟動了兩個相同的服務(wù),病人掛號的時候可能會出現(xiàn)同號的情況,比如兩個病人掛出來的號都是上午2號.這就出現(xiàn)了問題,由于是集群部署的,所以單純在代碼中的方法中加鎖是不能解決這種情況的.下面我將模擬這種情況,用redis做分布式鎖來解決這個問題.

1.新建掛號明細(xì)表

SpringBoot中使用redis做分布式鎖的方法

2.在idea上新建項(xiàng)目

SpringBoot中使用redis做分布式鎖的方法

SpringBoot中使用redis做分布式鎖的方法

SpringBoot中使用redis做分布式鎖的方法

下圖是創(chuàng)建好的項(xiàng)目結(jié)構(gòu),上面那個parent項(xiàng)目是其他項(xiàng)目不用管它,和新建的沒有關(guān)系

SpringBoot中使用redis做分布式鎖的方法

3.開始創(chuàng)建controller,service,dao(mapper),寫好后整體結(jié)構(gòu)如下

SpringBoot中使用redis做分布式鎖的方法

這里貼上service實(shí)現(xiàn)類的代碼,主要代碼就是這一塊:

package com.zk.service.impl; import com.zk.mapper.MzMapper;import com.zk.service.MzService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.HashMap;import java.util.Map; /** * 門診操作service實(shí)現(xiàn)類 * * @author zk * @date 2020-9-9 */@Servicepublic class MzServiceImpl implements MzService { @Autowired private MzMapper mzMapper; @Override public Map<String, Object> gh(String ksdm, String ysdm,String brid) { Map<String,Object> resultMap = new HashMap<>(); int ghxh = 0; //獲取當(dāng)前的掛號序號 Map<String, Object> ghxhMap = mzMapper.getGhxh(ksdm,ysdm); //如果為空,說明還沒有人掛這個醫(yī)生的號,當(dāng)前是一號 if(ghxhMap == null){ ghxh = 1; }else{ ghxh = (int)ghxhMap.get('GHXH'); ghxh++; } //實(shí)際場景中,先獲取到ghxh后,還會進(jìn)行收費(fèi)等其他操作,這里模擬一下需要耗費(fèi)時間,為了方便測試出現(xiàn)問題,這里時間設(shè)置稍微長一點(diǎn) try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //新增掛號明細(xì)記錄 mzMapper.addGhmx(ksdm,ysdm,ghxh,brid); resultMap.put('code','200'); resultMap.put('msg','success'); return resultMap; }}

4.進(jìn)行測試

1)清空數(shù)據(jù)庫表

2)使用postman發(fā)送post請求,假設(shè)ksdm=1表示皮膚科,ysdm=1表示醫(yī)生華佗,brbh=1表示張三,現(xiàn)在張三去醫(yī)院掛皮膚科華佗醫(yī)生的號,收費(fèi)員就會操作系統(tǒng)調(diào)用上面寫的掛號接口.

SpringBoot中使用redis做分布式鎖的方法

調(diào)用成功后,看看數(shù)據(jù)庫里的數(shù)據(jù)

SpringBoot中使用redis做分布式鎖的方法

可以看到張三掛到了華佗醫(yī)生的第一個號,接著把請求參數(shù)的brbh改成2表示李四,李四也去掛華佗醫(yī)生的號

SpringBoot中使用redis做分布式鎖的方法

請求成功后查看數(shù)據(jù)庫

SpringBoot中使用redis做分布式鎖的方法

可以看到李四掛了華佗醫(yī)生的第二個號.現(xiàn)在就是正常的掛號,沒有出現(xiàn)問題.

3)postman開第二個請求窗口,兩個窗口同時去掉接口進(jìn)行掛號

窗口一模擬張三掛號

SpringBoot中使用redis做分布式鎖的方法

窗口二模擬李四掛號

操作成功后看看數(shù)據(jù)庫

SpringBoot中使用redis做分布式鎖的方法

結(jié)果是張三和李四都掛到了三號,這就出現(xiàn)了線程安全問題.

3)使用加鎖的方式解決問題

SpringBoot中使用redis做分布式鎖的方法

方法加上鎖之后,測試確實(shí)沒有問題了,但是實(shí)際情況是集群部署的,并不是只有一個服務(wù)

4)啟動兩個服務(wù)

idea中設(shè)置允許啟動多個實(shí)例

SpringBoot中使用redis做分布式鎖的方法

修改端口號,第一個啟動的端口號是8080,這里改成8081

SpringBoot中使用redis做分布式鎖的方法

5)啟動兩個服務(wù)后再用postman去請求,張三請求8080服務(wù)接口

SpringBoot中使用redis做分布式鎖的方法

李四請求8081接口

SpringBoot中使用redis做分布式鎖的方法

兩個窗口同時請求的時候,再次出現(xiàn)了ghxh相同的情況,在方法上加同步鎖不能解決這個問題.

二.使用redis做分布式鎖解決問題

1.首先需要啟動一個redis,如果不知道redis怎么安裝使用的,可以看我之前寫的'redis的安裝和使用'.因?yàn)橹拔以谔摂M機(jī)上安裝過了redis,這里直接啟動一個單節(jié)點(diǎn)redis

SpringBoot中使用redis做分布式鎖的方法

2.項(xiàng)目的pom.xml文件引入redis依賴

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency>

3.在application.yml中配置redis

spring: redis: host: 192.168.1.6 port: 6379

4.新建redis鎖操作類

package com.zk.util; import org.apache.commons.lang3.StringUtils;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Repository; import java.util.UUID;import java.util.concurrent.TimeUnit; /** * redis鎖操作類 * * @author zk * @date 2020-9-10 */@Repositorypublic class RedisLock { private StringRedisTemplate stringredisTemplate; public RedisLock(StringRedisTemplate stringredisTemplate) { this.stringredisTemplate = stringredisTemplate; } /** * 加鎖,無阻塞 * 加鎖過程必須設(shè)置過期時間 * 如果沒有設(shè)置過期時間,手動釋放鎖的操作出現(xiàn)問題,那么就發(fā)生死鎖,鎖永遠(yuǎn)不能被釋放. * 加鎖和設(shè)置過期時間過程必須是原子操作 * 如果加鎖后服務(wù)宕機(jī)或程序崩潰,來不及設(shè)置過期時間,同樣會發(fā)生死鎖. * * @param key 鎖id * @param expire 過期時間 * @return */ public String tryLock(String key, long expire) { String token = UUID.randomUUID().toString(); //setIfAbsent方法:當(dāng)key不存在的時候,設(shè)置成功并返回true,當(dāng)key存在的時候,設(shè)置失敗并返回false //token是對應(yīng)的value,expire是緩存過期時間 Boolean isSuccess = stringredisTemplate.opsForValue().setIfAbsent(key, token, expire, TimeUnit.MILLISECONDS); if (isSuccess) { return token; } return null; } /** * 加鎖,有阻塞 * * @param name 鎖名稱 * @param expire 鎖過期時間 * @param timeout 請求超時時間 * @return */ public String lock(String name, long expire, long timeout) { long startTime = System.currentTimeMillis(); String token; do { token = tryLock(name, expire); if (token == null) { if ((System.currentTimeMillis() - startTime) > (timeout - 50)) { break; } try { //try 50 per sec Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); return null; } } } while (token == null); return token; } /** * 解鎖操作 * 解鎖必須是解除自己加上的鎖 * 試想一個這樣的場景,服務(wù)A加鎖,但執(zhí)行效率非常慢,導(dǎo)致鎖失效后還未執(zhí)行完,但這時候服務(wù)B已經(jīng)拿到鎖了,這時候服務(wù)A執(zhí)行完畢了去解鎖, * 把服務(wù)B的鎖給解掉了,其他服務(wù)C、D、E...都可以拿到鎖了,這就有問題了. * 加鎖的時候我們可以設(shè)置唯一value,解鎖時判斷是不是自己先前的value就行了. * * @param key * @param token * @return */ public boolean unlock(String key, String token) { //解鎖時需要先取出key對應(yīng)的value進(jìn)行判斷是否相等,這也是為什么加鎖的時候需要放不重復(fù)的值作為value String value = stringredisTemplate.opsForValue().get('name'); if (StringUtils.equals(value, token)) { stringredisTemplate.delete(key); return true; } return false; }}

5.修改業(yè)務(wù)操作類,用上RedisLock

package com.zk.service.impl; import com.zk.mapper.MzMapper;import com.zk.service.MzService;import com.zk.util.RedisLock;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service; import java.util.HashMap;import java.util.Map; /** * 門診操作service實(shí)現(xiàn)類 * * @author zk * @date 2020-9-9 */@Servicepublic class MzServiceImpl implements MzService { @Autowired private MzMapper mzMapper; @Autowired private RedisLock redisLock; @Override public Map<String, Object> gh(String ksdm, String ysdm, String brid) { Map<String, Object> resultMap = new HashMap<>(); int ghxh = 0; //加鎖操作 String token = null; token = redisLock.lock('gh', 3000,3500); try { //獲取到了鎖,執(zhí)行正常業(yè)務(wù) if (token != null) { //獲取當(dāng)前的掛號序號 Map<String, Object> ghxhMap = mzMapper.getGhxh(ksdm, ysdm); //如果為空,說明還沒有人掛這個醫(yī)生的號,當(dāng)前是一號 if (ghxhMap == null) { ghxh = 1; } else { ghxh = (int) ghxhMap.get('GHXH'); ghxh++; } //實(shí)際場景中,先獲取到ghxh后,還會進(jìn)行收費(fèi)等其他操作,這里模擬一下需要耗費(fèi)時間,為了方便測試出現(xiàn)問題,這里時間設(shè)置稍微長一點(diǎn) try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //新增掛號明細(xì)記錄 mzMapper.addGhmx(ksdm, ysdm, ghxh, brid); } else { resultMap.put('code', '401'); resultMap.put('msg', '其他窗口正在操作,請稍后再試'); return resultMap; } } finally { //解鎖 if (token != null) { boolean gh = redisLock.unlock('gh', token); } } resultMap.put('code', '200'); resultMap.put('msg', 'success'); return resultMap; }}

6.再用postman開兩個窗口去請求,和上面的操作一樣,然后再看數(shù)據(jù)庫的數(shù)據(jù)

SpringBoot中使用redis做分布式鎖的方法

問題解決,不會再出現(xiàn)重復(fù)的ghxh.

總結(jié)

到此這篇關(guān)于SpringBoot中使用redis做分布式鎖的方法的文章就介紹到這了,更多相關(guān)SpringBoot redis分布式鎖內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 深圳宣传片制作_产品视频制作_深圳3D动画制作公司_深圳短视频拍摄-深圳市西典映画传媒有限公司 | 广东健伦体育发展有限公司-体育工程配套及销售运动器材的体育用品服务商 | 铝板冲孔网,不锈钢冲孔网,圆孔冲孔网板,鳄鱼嘴-鱼眼防滑板,盾构走道板-江拓数控冲孔网厂-河北江拓丝网有限公司 | 三氯异氰尿酸-二氯-三氯-二氯异氰尿酸钠-优氯净-强氯精-消毒片-济南中北_优氯净厂家 | 影视模板素材_原创专业影视实拍视频素材-8k像素素材网 | 电竞馆加盟,沈阳网吧加盟费用选择嘉棋电竞_售后服务一体化 | 事迹材料_个人事迹名人励志故事| 单电机制砂机,BHS制砂机,制沙机设备,制砂机价格-正升制砂机厂家 单级/双级旋片式真空泵厂家,2xz旋片真空泵-浙江台州求精真空泵有限公司 | 杜康白酒加盟_杜康酒代理_杜康酒招商加盟官网_杜康酒厂加盟总代理—杜康酒神全国运营中心 | 重庆钣金加工厂家首页-专业定做监控电视墙_操作台 | 招商帮-一站式网络营销服务|搜索营销推广|信息流推广|短视视频营销推广|互联网整合营销|网络推广代运营|招商帮企业招商好帮手 | 深圳货架厂_仓库货架公司_重型仓储货架_线棒货架批发-深圳市诺普泰仓储设备有限公司 | 电缆故障测试仪_电缆故障定位仪_探测仪_检测仪器_陕西意联电气厂家 | 澳威全屋定制官网|极简衣柜十大品牌|衣柜加盟代理|全屋定制招商 百度爱采购运营研究社社群-店铺托管-爱采购代运营-良言多米网络公司 | 警用|治安|保安|不锈钢岗亭-售货亭价格-垃圾分类亭-移动厕所厂家-苏州灿宇建材 | 河北中仪伟创试验仪器有限公司是专业生产沥青,土工,水泥,混凝土等试验仪器的厂家,咨询电话:13373070969 | 今日热点_实时热点_奇闻异事_趣闻趣事_灵异事件 - 奇闻事件 | 六维力传感器_六分量力传感器_模腔压力传感器-南京数智微传感科技有限公司 | 口臭的治疗方法,口臭怎么办,怎么除口臭,口臭的原因-口臭治疗网 | 苹果售后维修点查询,苹果iPhone授权售后维修服务中心 – 修果网 拼装地板,悬浮地板厂家,悬浮式拼装运动地板-石家庄博超地板科技有限公司 | 济南画室培训-美术高考培训-山东艺霖艺术培训画室 | Eiafans.com_环评爱好者 环评网|环评论坛|环评报告公示网|竣工环保验收公示网|环保验收报告公示网|环保自主验收公示|环评公示网|环保公示网|注册环评工程师|环境影响评价|环评师|规划环评|环评报告|环评考试网|环评论坛 - Powered by Discuz! | 超声波清洗机-超声波清洗设备定制生产厂家 - 深圳市冠博科技实业有限公司 | 全自动贴标机-套标机-工业热风机-不干胶贴标机-上海厚冉机械 | 仿古建筑设计-仿古建筑施工-仿古建筑公司-汉匠古建筑设计院 | 德国BOSCH电磁阀-德国HERION电磁阀-JOUCOMATIC电磁阀|乾拓百科 | 水上浮桥-游艇码头-浮动码头-游船码头-码瑞纳游艇码头工程 | 广东护栏厂家-广州护栏网厂家-广东省安麦斯交通设施有限公司 | 钢托盘,铁托盘,钢制托盘,镀锌托盘,饲料托盘,钢托盘制造商-南京飞天金属13260753852 | 气弹簧定制-气动杆-可控气弹簧-不锈钢阻尼器-工业气弹簧-可调节气弹簧厂家-常州巨腾气弹簧供应商 | 防勒索软件_数据防泄密_Trellix(原McAfee)核心代理商_Trellix(原Fireeye)售后-广州文智信息科技有限公司 | 光谱仪_积分球_分布光度计_灯具检测生产厂家_杭州松朗光电【官网】 | 手术示教系统-数字化手术室系统-林之硕医疗云智能视频平台 | 北京网站建设|北京网站开发|北京网站设计|高端做网站公司 | 黑田精工电磁阀-CAMMOZI气缸-ROSS电磁-上海茂硕机械设备有限公司 | 阿尔法-MDR2000无转子硫化仪-STM566 SATRA拉力试验机-青岛阿尔法仪器有限公司 | 氨水-液氨-工业氨水-氨水生产厂家-辽宁顺程化工 | 济南冷库安装-山东冷库设计|建造|冷库维修-山东齐雪制冷设备有限公司 | 成都思迪机电技术研究所-四川成都思迪编码器 | 广西绿桂涂料--承接隔热涂料、隔音涂料、真石漆、多彩仿石漆等涂料工程双包施工 | 电磁流量计厂家_涡街流量计厂家_热式气体流量计-青天伟业仪器仪表有限公司 |