Springboot在有鎖的情況下正確使用事務(wù)的實(shí)現(xiàn)代碼
1. 概述
老話說的好:想要賺錢,就去看看有錢人有什么需求,因?yàn)橛绣X人錢多,所以賺的多。
言歸正傳,在Java項(xiàng)目的研發(fā)中,“鎖”這個(gè)詞并不陌生,最經(jīng)典的使用場(chǎng)景是商品的超賣問題。
很多Java小白,通常會(huì)認(rèn)為,給代碼加上一把“鎖”,就能解決多扣庫(kù)存問題,卻忽略了數(shù)據(jù)庫(kù)事務(wù)的問題,今天我們就來做一個(gè)實(shí)驗(yàn),分析一下商品超賣問題。
2. 場(chǎng)景介紹
有一款商品,庫(kù)存只剩1件。
購(gòu)買商品時(shí),做三個(gè)動(dòng)作,一是檢查庫(kù)存,二是扣庫(kù)存,三是生成訂單,三個(gè)動(dòng)作在一個(gè)事務(wù)中執(zhí)行。
模擬并發(fā)場(chǎng)景,使用10個(gè)線程同時(shí)執(zhí)行用戶購(gòu)買商品的操作。
3. 代碼實(shí)現(xiàn)
3.1 不加鎖的代碼實(shí)現(xiàn)
@Transactional(rollbackFor = Exception.class)
public void buy() {
// 查看是商品否有庫(kù)存
Integer count = getProductCount();
if(count <= 0) {
throw new RuntimeException("庫(kù)存為 0");
}
// 減庫(kù)存
productRepository.reductCount();
// 生成訂單
createOrder();
}
首先我們正常編寫業(yè)務(wù)邏輯,用 @Transactional 注解控制事務(wù)。
經(jīng)并發(fā)實(shí)驗(yàn),產(chǎn)生了超賣的現(xiàn)象。
3.2 加鎖的代碼實(shí)現(xiàn)
@Transactional(rollbackFor = Exception.class)
public synchronized void buy() {
// 查看是商品否有庫(kù)存
Integer count = getProductCount();
if(count <= 0) {
throw new RuntimeException("庫(kù)存為 0");
}
// 減庫(kù)存
productRepository.reductCount();
// 生成訂單
createOrder();
}
這次我們使用 synchronized 關(guān)鍵字給方法加了把“鎖”,理論上應(yīng)該不會(huì)產(chǎn)生超賣現(xiàn)象了吧。
經(jīng)實(shí)驗(yàn),仍然產(chǎn)生了超賣現(xiàn)象。
因?yàn)殡m然方法被鎖住了,可是@Transactional 注解并沒有及時(shí)的提交事務(wù),導(dǎo)致庫(kù)存沒有及時(shí)扣減為0,因此還是超賣了。
3.3 正確使用事務(wù)的代碼實(shí)現(xiàn)
@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
// @Transactional(rollbackFor = Exception.class)
public synchronized void buy() {
// 開啟事務(wù)
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
try {
// 查看是商品否有庫(kù)存
Integer count = getProductCount();
if(count <= 0) {
throw new RuntimeException("庫(kù)存為 0");
}
// 減庫(kù)存
productRepository.reductCount();
// 生成訂單
createOrder();
// 事務(wù)提交
platformTransactionManager.commit(transactionStatus);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
// 事務(wù)回滾
platformTransactionManager.rollback(transactionStatus);
}
}
這次我們不使用@Transactional 注解管理事務(wù)了,改為手動(dòng)管理事務(wù)。
經(jīng)實(shí)驗(yàn),解決了超賣現(xiàn)象。
4. 綜述
今天聊了一下 Springboot在有鎖的情況下如何正確使用事務(wù),希望可以對(duì)大家的工作有所幫助。
到此這篇關(guān)于Springboot在有鎖的情況下如何正確使用事務(wù)的文章就介紹到這了,更多相關(guān)Springboot使用事務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot解決406錯(cuò)誤之返回對(duì)象缺少Getter/Setter方法引發(fā)的問題
在Spring Boot開發(fā)中,接口請(qǐng)求返回?cái)?shù)據(jù)是系統(tǒng)交互的重要環(huán)節(jié),然而,開發(fā)過程中常常會(huì)遇到由于數(shù)據(jù)類型或返回格式問題導(dǎo)致的錯(cuò)誤,其中最常見的就是406 Not Acceptable異常,本篇文章以實(shí)際的案例出發(fā),詳細(xì)分析在POST請(qǐng)求中產(chǎn)生406錯(cuò)誤的原因2024-11-11
Java 5個(gè)人坐在一起(有關(guān)第五個(gè)人歲數(shù)的問題)
利用遞歸的方法,遞歸分為回推和遞推兩個(gè)階段。要想知道第五個(gè)人歲數(shù),需知道第四人的歲數(shù),依次類推,推到第一人(10歲),再往回推,需要的朋友可以參考下2017-02-02
Java JFinal框架中實(shí)現(xiàn)添加定時(shí)任務(wù)功能詳解
這篇文章主要為大家詳細(xì)介紹了如何在JFinal框架項(xiàng)目中添加定時(shí)任務(wù)的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02
Mybatis調(diào)用Oracle存儲(chǔ)過程的方法圖文詳解
這篇文章主要介紹了Mybatis調(diào)用Oracle存儲(chǔ)過程的方法介紹,需要的朋友可以參考下2017-09-09
Java語(yǔ)言通過三種方法實(shí)現(xiàn)隊(duì)列的示例代碼
這篇文章主要介紹了Java語(yǔ)言通過三種方法來實(shí)現(xiàn)隊(duì)列的實(shí)例代碼,數(shù)組模擬隊(duì)列,通過對(duì)定義的了解,發(fā)現(xiàn)隊(duì)列很像我們的數(shù)組,下面我們通過實(shí)踐給大家詳細(xì)介紹,需要的朋友可以參考下2022-02-02

