日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

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

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

一.模擬問題

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

1.新建掛號明細表

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

2.在idea上新建項目

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

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

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

下圖是創建好的項目結構,上面那個parent項目是其他項目不用管它,和新建的沒有關系

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

3.開始創建controller,service,dao(mapper),寫好后整體結構如下

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

這里貼上service實現類的代碼,主要代碼就是這一塊:

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實現類 * * @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; //獲取當前的掛號序號 Map<String, Object> ghxhMap = mzMapper.getGhxh(ksdm,ysdm); //如果為空,說明還沒有人掛這個醫生的號,當前是一號 if(ghxhMap == null){ ghxh = 1; }else{ ghxh = (int)ghxhMap.get('GHXH'); ghxh++; } //實際場景中,先獲取到ghxh后,還會進行收費等其他操作,這里模擬一下需要耗費時間,為了方便測試出現問題,這里時間設置稍微長一點 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //新增掛號明細記錄 mzMapper.addGhmx(ksdm,ysdm,ghxh,brid); resultMap.put('code','200'); resultMap.put('msg','success'); return resultMap; }}

4.進行測試

1)清空數據庫表

2)使用postman發送post請求,假設ksdm=1表示皮膚科,ysdm=1表示醫生華佗,brbh=1表示張三,現在張三去醫院掛皮膚科華佗醫生的號,收費員就會操作系統調用上面寫的掛號接口.

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

調用成功后,看看數據庫里的數據

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

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

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

請求成功后查看數據庫

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

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

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

窗口一模擬張三掛號

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

窗口二模擬李四掛號

操作成功后看看數據庫

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

結果是張三和李四都掛到了三號,這就出現了線程安全問題.

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

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

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

4)啟動兩個服務

idea中設置允許啟動多個實例

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

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

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

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

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

李四請求8081接口

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

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

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

1.首先需要啟動一個redis,如果不知道redis怎么安裝使用的,可以看我之前寫的'redis的安裝和使用'.因為之前我在虛擬機上安裝過了redis,這里直接啟動一個單節點redis

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

2.項目的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; } /** * 加鎖,無阻塞 * 加鎖過程必須設置過期時間 * 如果沒有設置過期時間,手動釋放鎖的操作出現問題,那么就發生死鎖,鎖永遠不能被釋放. * 加鎖和設置過期時間過程必須是原子操作 * 如果加鎖后服務宕機或程序崩潰,來不及設置過期時間,同樣會發生死鎖. * * @param key 鎖id * @param expire 過期時間 * @return */ public String tryLock(String key, long expire) { String token = UUID.randomUUID().toString(); //setIfAbsent方法:當key不存在的時候,設置成功并返回true,當key存在的時候,設置失敗并返回false //token是對應的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; } /** * 解鎖操作 * 解鎖必須是解除自己加上的鎖 * 試想一個這樣的場景,服務A加鎖,但執行效率非常慢,導致鎖失效后還未執行完,但這時候服務B已經拿到鎖了,這時候服務A執行完畢了去解鎖, * 把服務B的鎖給解掉了,其他服務C、D、E...都可以拿到鎖了,這就有問題了. * 加鎖的時候我們可以設置唯一value,解鎖時判斷是不是自己先前的value就行了. * * @param key * @param token * @return */ public boolean unlock(String key, String token) { //解鎖時需要先取出key對應的value進行判斷是否相等,這也是為什么加鎖的時候需要放不重復的值作為value String value = stringredisTemplate.opsForValue().get('name'); if (StringUtils.equals(value, token)) { stringredisTemplate.delete(key); return true; } return false; }}

5.修改業務操作類,用上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實現類 * * @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 { //獲取到了鎖,執行正常業務 if (token != null) { //獲取當前的掛號序號 Map<String, Object> ghxhMap = mzMapper.getGhxh(ksdm, ysdm); //如果為空,說明還沒有人掛這個醫生的號,當前是一號 if (ghxhMap == null) { ghxh = 1; } else { ghxh = (int) ghxhMap.get('GHXH'); ghxh++; } //實際場景中,先獲取到ghxh后,還會進行收費等其他操作,這里模擬一下需要耗費時間,為了方便測試出現問題,這里時間設置稍微長一點 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //新增掛號明細記錄 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開兩個窗口去請求,和上面的操作一樣,然后再看數據庫的數據

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

問題解決,不會再出現重復的ghxh.

總結

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

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲我射av| 亚洲一区二区av| 欧美91在线|欧美| 成人国产精品久久| 国产综合婷婷| 日韩综合一区二区| 欧美激情麻豆| 久久精品卡一| 婷婷视频一区二区三区| 精品一区二区三区中文字幕在线| 欧产日产国产精品视频| 99国产精品视频免费观看一公开 | 狠狠色综合网| 日本91福利区| 天堂8中文在线最新版在线| 亚洲成人日韩| 日韩成人av影视| 亚洲成人不卡| 日韩美女精品| 超碰成人av| 蜜桃视频一区二区三区在线观看| 国产精品久久乐| 亚洲韩日在线| 欧美亚洲二区| 国产99精品| 国产精品免费99久久久| 欧美手机在线| 国产情侣一区| 91久久久精品国产| 国产精品videossex| 欧美精品一二| 国产精品尤物| 午夜亚洲一区| 四虎成人av| 日韩精品一级| 国产精品黄网站| www.51av欧美视频| 老司机久久99久久精品播放免费| 久久三级视频| 天堂俺去俺来也www久久婷婷| 欧美不卡高清一区二区三区| 国产成人精品亚洲线观看| 国产一区二区三区久久| 亚洲免费成人| 国产精品多人| 欧洲精品一区二区三区| 日韩福利视频导航| 国产综合激情| 97精品国产| 国产亚洲精品美女久久| 香蕉精品999视频一区二区| 日韩88av| 国产精品亚洲人成在99www| 免费日韩一区二区| 特黄特色欧美大片| 精品一区二区三区视频在线播放 | 国产精品毛片一区二区三区| 国产成人精品三级高清久久91| 亚洲一二av| 日韩影院二区| 美日韩一区二区三区| 日韩激情一二三区| 丝袜诱惑制服诱惑色一区在线观看 | 亚洲综合激情在线| 免费久久精品| 成人日韩精品| 麻豆高清免费国产一区| 日韩影片在线观看| 亚洲成人三区| 久久久久久久久久久妇女 | 先锋亚洲精品| 1000部精品久久久久久久久| 91亚洲国产成人久久精品| 国产精品久久久久毛片大屁完整版| 中文不卡在线| 亚洲综合日韩| 亚洲免费影视| 亚洲精品小说| 欧美1区2区3区| 日韩在线免费| 国产不卡av一区二区| 国产乱码精品一区二区三区四区 | 免费美女久久99| 亚洲经典在线| 在线一区视频| 亚洲一区日韩| 国产免费成人| 亚洲专区一区| 日韩在线a电影| 亚洲香蕉久久| 一本一道久久a久久| 国产精品普通话对白| 婷婷成人基地| 亚洲免费高清| 蜜臀久久久久久久| 久久夜色精品| 亚洲91在线| 日韩高清不卡一区二区| 国产视频网站一区二区三区| 国产精品一区二区av交换| 久久av超碰| 精品中文字幕一区二区三区四区| 久久女人天堂| 人在线成免费视频| 婷婷成人在线| 午夜欧美精品久久久久久久| 亚洲夜间福利| 在线视频精品| 综合激情网站| 欧美天堂一区| 成人污污视频| 欧美日韩免费观看视频| 99久久亚洲精品蜜臀| 亚洲一区黄色| 日韩毛片网站| 国产精品白浆| 欧产日产国产精品视频| 一区二区自拍| 日韩精品久久久久久久软件91| 国产精品一区二区精品| www在线观看黄色| 亚洲天堂成人| 亚洲18在线| 久久亚洲人体| 99久久99视频只有精品| 巨乳诱惑日韩免费av| 欧美影院精品| 成人欧美一区二区三区的电影| 午夜免费一区| 日韩精品一区二区三区中文在线| 国产精品亲子伦av一区二区三区| 国产精品精品| 在线综合视频| 国产精品中文| 99精品综合| 日产欧产美韩系列久久99| 久久91视频| 一本色道精品久久一区二区三区| 欧美一区网站| 亚洲天堂1区| 中文字幕一区二区三区日韩精品 | 国产精品久久久久久久久久10秀 | 蜜臀va亚洲va欧美va天堂| 久久国产麻豆精品| 四虎4545www国产精品| 亚洲在线久久| 久久精品国产福利| 黄色成人91| 国产精品久av福利在线观看| 久久国产日本精品| 日韩一区二区三区精品| а√在线中文在线新版| 免费久久99精品国产自在现线| 国产精品白丝一区二区三区| 国产精品av久久久久久麻豆网| 日韩精品亚洲专区在线观看| 天堂√中文最新版在线| 婷婷综合一区| 蜜臀久久精品| 日韩av一二三| 999精品一区| 国产亚洲精品美女久久| 999国产精品视频| 国产人成精品一区二区三| 九九久久婷婷| 麻豆精品蜜桃视频网站| 99亚洲视频| 欧美黄色一区二区| 蜜桃av一区| 日韩一区自拍| 日本午夜精品久久久久| 久久香蕉国产| 欧美激情福利| 亚洲资源网站| 久久久久国产| 麻豆中文一区二区| 久久先锋影音| 天堂中文av在线资源库| 啪啪亚洲精品| 野花国产精品入口| 中文字幕在线视频网站| 欧美日韩黄网站| 久久国产精品久久w女人spa| 亚洲黄色网址| 国产精品一区二区三区www| 男人的天堂亚洲一区| 久久蜜桃精品| 成人日韩av| 国产日韩在线观看视频| 巨乳诱惑日韩免费av| 久久国产日韩| 国产一区二区精品久| 亚洲一区二区三区四区电影 | 欧美在线综合| 日本一区二区高清不卡| 国产欧美丝祙| 日韩精品一区二区三区中文在线| 亚洲一区免费| 不卡一区2区| 亚洲精品88|