Springboot使用redisson實現(xiàn)分布式鎖的代碼示例
一、前言
在實際項目中,某些場景下可能需要使用到分布式鎖功能,那么實現(xiàn)分布式鎖有多種方式,常見的如mysql分布式鎖、zookeeper分布式鎖、redis分布式鎖,從效率上講,redis無疑是性能最好的,但也會存在一些問題
1.獲取鎖的線程在執(zhí)行任務(wù)的過程中掛掉,來不及釋放鎖,這塊資源將會永遠被鎖?。ㄋ梨i),別的線程再也別想進來,因此我們需要給key加個過期時間,保證這把鎖要在一定時間后自動釋放。
2.高并發(fā)情況下redis分布式鎖永久失效 的問題(一個線程可能刪除了別的線程的鎖)
假設(shè)線程 A 可能某些原因執(zhí)行的很慢很慢,到達過期時間都沒執(zhí)行完,這時候鎖過期自動釋放,此時線程 B 得到了鎖;
隨后,線程 A 執(zhí)行完了任務(wù),線程 A 隨之釋放鎖。但這時候線程 B 還沒執(zhí)行完,線程A實際上 刪除的是線程 B加的鎖
解決方法:
可以在 釋放鎖之前做一個判斷,驗證當前的鎖是不是自己加的鎖
3.可能出現(xiàn)并發(fā)情況
當線程 A 執(zhí)行的很慢很慢,到達過期時間都沒執(zhí)行完,這時候鎖過期自動釋放,線程 B得到了鎖。此時就有多個線程在訪問同步代碼塊。
解決方法:我們可以使用redisson實現(xiàn),內(nèi)部實現(xiàn)鎖續(xù)期功能。
二、實現(xiàn)
1.在springboot中引入redisson依賴包
<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.我們以商品庫存為例:
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 "當前數(shù)量為0,不能再扣了?。?;
}
product .setQuanlity(product .getQuanlity()-1);
productMapper.updateById(product );
result = "當前數(shù)量:" + product .getQuanlity();
System.err.println(result);
}catch (Exception e) {
System.err.println(e.getMessage());
throw new RuntimeException("扣庫存操作失敗了");
}finally {
lock.unlock();
}
return result;
}
}這就是實現(xiàn)分布式鎖常見場景。
4.接著我們可以在controller層調(diào)用,我們可以模擬多線程操作,看扣庫存是否會有問題。
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實現(xiàn)分布式鎖的代碼示例的文章就介紹到這了,更多相關(guān)Springboot redisson實現(xiàn)分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springmvc前臺向后臺傳值幾種方式總結(jié)(從簡單到復(fù)雜)
今天小編就為大家分享一篇springmvc前臺向后臺傳值幾種方式總結(jié)(從簡單到復(fù)雜),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
Java設(shè)計模式之橋接模式詳解(Bridge Pattern)
橋接模式是一種結(jié)構(gòu)型設(shè)計模式,旨在將抽象部分與其實現(xiàn)部分分離,從而使兩者可以獨立地變化,橋接模式通過組合關(guān)系代替繼承關(guān)系,將抽象和實現(xiàn)解耦,使代碼更具擴展性和維護性2025-02-02
vue+springboot+webtrc+websocket實現(xiàn)雙人音視頻通話會議(最新推薦)
這篇文章主要介紹了vue+springboot+webtrc+websocket實現(xiàn)雙人音視頻通話會議,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2025-05-05

