Springboot使用redisson實(shí)現(xiàn)分布式鎖的代碼示例
一、前言
在實(shí)際項(xiàng)目中,某些場(chǎng)景下可能需要使用到分布式鎖功能,那么實(shí)現(xiàn)分布式鎖有多種方式,常見(jiàn)的如mysql分布式鎖、zookeeper分布式鎖、redis分布式鎖,從效率上講,redis無(wú)疑是性能最好的,但也會(huì)存在一些問(wèn)題
1.獲取鎖的線程在執(zhí)行任務(wù)的過(guò)程中掛掉,來(lái)不及釋放鎖,這塊資源將會(huì)永遠(yuǎn)被鎖住(死鎖),別的線程再也別想進(jìn)來(lái),因此我們需要給key加個(gè)過(guò)期時(shí)間,保證這把鎖要在一定時(shí)間后自動(dòng)釋放。
2.高并發(fā)情況下redis分布式鎖永久失效 的問(wèn)題(一個(gè)線程可能刪除了別的線程的鎖)
假設(shè)線程 A 可能某些原因執(zhí)行的很慢很慢,到達(dá)過(guò)期時(shí)間都沒(méi)執(zhí)行完,這時(shí)候鎖過(guò)期自動(dòng)釋放,此時(shí)線程 B 得到了鎖;
隨后,線程 A 執(zhí)行完了任務(wù),線程 A 隨之釋放鎖。但這時(shí)候線程 B 還沒(méi)執(zhí)行完,線程A實(shí)際上 刪除的是線程 B加的鎖
解決方法:
可以在 釋放鎖之前做一個(gè)判斷,驗(yàn)證當(dāng)前的鎖是不是自己加的鎖
3.可能出現(xiàn)并發(fā)情況
當(dāng)線程 A 執(zhí)行的很慢很慢,到達(dá)過(guò)期時(shí)間都沒(méi)執(zhí)行完,這時(shí)候鎖過(guò)期自動(dòng)釋放,線程 B得到了鎖。此時(shí)就有多個(gè)線程在訪問(wèn)同步代碼塊。
解決方法:我們可以使用redisson實(shí)現(xiàn),內(nèi)部實(shí)現(xiàn)鎖續(xù)期功能。
二、實(shí)現(xiàn)
1.在springboot中引入redisson依賴(lài)包
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.10.6</version>
</dependency>2.配置redisson,代碼如下:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
@Configuration
public class RedissonConfig {
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() throws IOException{
//RedissonClient redisson = Redisson.create(Config.fromYAML(new //ClassPathResource("redisson-single.yml").getInputStream()));
Config config = new Config();
config.useSingleServer()
.setAddress("redis://192.168.6.52:6379").setPassword("123456")
.setRetryInterval(5000)
.setTimeout(10000)
.setConnectTimeout(10000);
return Redisson.create(config);
}
}3.我們以商品庫(kù)存為例:
import java.util.concurrent.TimeUnit;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.suntree.entity.Price;
import com.suntree.mapper.PriceMapper;
@Service
public class ProductService {
@Autowired
RedissonClient redissonClient;
@Autowired
ProductMapper productMapper;
@Transactional
public String descreaseProduct(String productId,Integer quanlity) {
String key="des_product_lock:"+productId;
RLock lock=redissonClient.getLock(key);
lock.lock();
Product product =productMapper.selectById(productId);
if(product ==null) {
return "產(chǎn)品未找到";
}
String result="";
try {
if(product .getQuanlity()==0) {
return "當(dāng)前數(shù)量為0,不能再扣了??!";
}
product .setQuanlity(product .getQuanlity()-1);
productMapper.updateById(product );
result = "當(dāng)前數(shù)量:" + product .getQuanlity();
System.err.println(result);
}catch (Exception e) {
System.err.println(e.getMessage());
throw new RuntimeException("扣庫(kù)存操作失敗了");
}finally {
lock.unlock();
}
return result;
}
}這就是實(shí)現(xiàn)分布式鎖常見(jiàn)場(chǎng)景。
4.接著我們可以在controller層調(diào)用,我們可以模擬多線程操作,看扣庫(kù)存是否會(huì)有問(wèn)題。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.suntree.service.ProductService ;
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
ProductService productService ;
@GetMapping("/descrease")
public String descreaseProduct() {
return productService .descreaseProduct("2020-2020", 200);
}
}大家可以自己嘗試下。
到此這篇關(guān)于Springboot使用redisson實(shí)現(xiàn)分布式鎖的代碼示例的文章就介紹到這了,更多相關(guān)Springboot redisson實(shí)現(xiàn)分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 基于SpringBoot+Redis實(shí)現(xiàn)分布式鎖
- 如何在SpringBoot中使用Redis實(shí)現(xiàn)分布式鎖
- SpringBoot RedisTemplate分布式鎖的項(xiàng)目實(shí)戰(zhàn)
- SpringBoot基于Redis的分布式鎖實(shí)現(xiàn)過(guò)程記錄
- 關(guān)于SpringBoot 使用 Redis 分布式鎖解決并發(fā)問(wèn)題
- SpringBoot整合Redisson實(shí)現(xiàn)分布式鎖
- springboot 集成redission 以及分布式鎖的使用詳解
- SpringBoot之使用Redis實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng))
- SpringBoot集成redis實(shí)現(xiàn)分布式鎖的示例代碼
- 基于springboot實(shí)現(xiàn)redis分布式鎖的方法
- Springboot中使用Redis實(shí)現(xiàn)分布式鎖的示例代碼
相關(guān)文章
Java 關(guān)鍵字static詳解及實(shí)例代碼
這篇文章主要介紹了Java 關(guān)鍵字static詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(28)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07
ScrollView中嵌入ListView只顯示一條的解決辦法
在ScrollView添加一個(gè)ListView會(huì)導(dǎo)致listview控件顯示不全,通常只會(huì)顯示一條,究竟是什么原因呢?下面腳本之家小編給大家介紹ScrollView中嵌入ListView只顯示一條的解決辦法,感興趣的朋友一起學(xué)習(xí)吧2016-05-05
JAVA實(shí)現(xiàn)數(shù)字大寫(xiě)金額轉(zhuǎn)換的方法
這篇文章主要介紹了JAVA實(shí)現(xiàn)數(shù)字大寫(xiě)金額轉(zhuǎn)換的方法,涉及java針對(duì)字符串與數(shù)組的遍歷與轉(zhuǎn)換相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
java項(xiàng)目中常用指標(biāo)UV?PV?QPS?TPS含義以及統(tǒng)計(jì)方法
文章介紹了現(xiàn)代Web應(yīng)用中性能監(jiān)控和分析的重要性,涵蓋了UV、PV、QPS、TPS等關(guān)鍵指標(biāo)的統(tǒng)計(jì)方法,并提供了示例代碼,同時(shí),文章還討論了性能優(yōu)化和瓶頸分析的策略,以及使用Grafana等可視化工具進(jìn)行監(jiān)控與告警的重要性2025-01-01
springBoo3.0集成knife4j4.1.0的詳細(xì)教程(swagger3)
這篇文章主要介紹了springBoo3.0集成knife4j4.1.0的詳細(xì)教程(swagger3),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
Java編譯錯(cuò)誤問(wèn)題:需要class,interface或enum
這篇文章主要介紹了Java編譯錯(cuò)誤問(wèn)題:需要class,interface或enum,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
springboot項(xiàng)目中配置redis詳細(xì)的教程
Redis是一種高性能的鍵值存儲(chǔ)數(shù)據(jù)庫(kù),而Spring Boot是一個(gè)簡(jiǎn)化了開(kāi)發(fā)過(guò)程的Java框架,這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目中配置redis詳細(xì)的教程,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04

