SpringBoot異步任務(wù)實(shí)現(xiàn)下單校驗(yàn)庫存的項(xiàng)目實(shí)踐
??前言
在開發(fā)中,異步任務(wù)應(yīng)用的場景非常的廣泛,本文章以下單時(shí)校驗(yàn)庫存為例來看看SpringBoot中異步任務(wù)的使用。使用異步任務(wù)可以提高系統(tǒng)的響應(yīng)性能,提高系統(tǒng)的并發(fā)能力,改善用戶體驗(yàn),減少資源的浪費(fèi),提高系統(tǒng)的可擴(kuò)展性。
??思維導(dǎo)圖

??流程圖

??必不可少的注解
@EnableAsync:用于標(biāo)識啟動(dòng)類,開啟異步任務(wù)。@Component:標(biāo)識異步任務(wù)類。@Async:標(biāo)識定時(shí)任務(wù)方法。
??獲取異步結(jié)果的API
| 方法 | 描述 |
|---|---|
boolean cancel(boolean mayInterruptIfRunning) | 取消異步任務(wù)的執(zhí)行。 |
boolean isCancelled() | 判斷異步任務(wù)是否被取消。 |
boolean isDone() | 判斷異步任務(wù)是否已經(jīng)完成。 |
V get() throws InterruptedException, ExecutionException | 獲取異步任務(wù)的結(jié)果。 |
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException | 在指定的時(shí)間內(nèi)獲取異步任務(wù)的結(jié)果。如果超時(shí),會(huì)拋出TimeoutException。 |
??實(shí)現(xiàn)步驟
數(shù)據(jù)準(zhǔn)備
創(chuàng)建數(shù)據(jù)庫表,并插入示例數(shù)據(jù)
CREATE TABLE product ( id INT PRIMARY KEY, name VARCHAR(100), price DECIMAL(10,2), stock INT ); INSERT INTO product (id, name, price, stock) VALUES (1, '蘋果13', 10.99, 50), (2, '小米10', 19.99, 100), (3, '華為mate20', 5.99, 20);
實(shí)體類
public class Product {
private Integer id;
private String name;
private BigDecimal price;
private Integer stock;
}啟動(dòng)類開啟異步任務(wù)
添加@EnableAsync開啟異步任務(wù)。
@SpringBootApplication
@MapperScan("com.shoanjen.redis.mapper")
@EnableCaching
@EnableScheduling
@EnableAsync
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}異步任務(wù)方法
在異步任務(wù)方法上添加@Async注解。
方法邏輯:
- 根據(jù)商品id查詢數(shù)據(jù)庫是否存在當(dāng)前商品
- 若商品不存在、或者商品當(dāng)前庫存小于購買量quantity,返回false。
- 若商品存在,進(jìn)行模擬下單操作。更新庫存的數(shù)量。
- 當(dāng)然還有查詢余額的邏輯,我這里沒有寫,跟查詢庫存類似。
優(yōu)點(diǎn):通過異步任務(wù)實(shí)現(xiàn)下單時(shí)查詢庫存以及余額,可以很大的提高性能。
@Component
public class ValidateTask {
@Autowired
private ProductMapper productMapper;
//校驗(yàn)庫存功能
@Async
public Future<Boolean> validateStock(int productId, int quantity){
//查詢數(shù)據(jù)庫中的商品
Product product=productMapper.selectProductById(productId);
//商品庫存校驗(yàn)
if (product==null || product.getStock()<quantity){
return new AsyncResult<>(false);
}else {
//模擬下單操作
product.setStock(product.getStock()-quantity);
//這里就演示訂單表保存數(shù)據(jù)了,直接更新庫存
productMapper.updateProduct(product);
return new AsyncResult<>(true);
}
}
}Controller層
方法邏輯:
- 調(diào)用異步任務(wù)。
- 設(shè)置flag標(biāo)記。
- 判斷異步任務(wù)是否完成。
- 如果flag為true,則下單成功,否則失敗。
@RestController
@RequestMapping("/api/v1/product")
public class ProductController {
@Autowired
private ValidateTask validateTask;
//productId-商品id,quantity-購買數(shù)量
@RequestMapping("order")
public JsonData order(@RequestParam int productId,@RequestParam int quantity) throws ExecutionException, InterruptedException {
//調(diào)用異步任務(wù)
Future<Boolean> validateResult=validateTask.validateStock(productId,quantity);
Boolean flag=false;
//判斷異步任務(wù)是否完成
if (validateResult.isDone()){
try {
flag=validateResult.get();
} catch (Exception e) {
flag=false;
}
}
if (flag){
return JsonData.buildSuccess("下單成功");
}else {
return JsonData.buildError("下單失敗,庫存不足");
}
}ProductMapper.xml
<mapper namespace="com.shoanjen.redis.mapper.ProductMapper">
<select id="selectProductById" resultType="com.shoanjen.redis.model.Product">
select * from product where id=#{productId}
</select>
<update id="updateProduct" parameterType="com.shoanjen.redis.model.Product">
update product set name=#{product.name},price=#{product.price},stock=#{product.stock} where id=#{product.id}
</update>
</mapper>效果測試

下單成功測試

庫存不足測試

??寫在最后
有關(guān)于SpringBoot異步任務(wù)實(shí)現(xiàn)下單校驗(yàn)庫存的實(shí)戰(zhàn)到此就結(jié)束了,更多相關(guān)SpringBoot 下單校驗(yàn)庫存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java的finally塊居然沒執(zhí)行的6種問題解決
本文探討了Java中try-catch-finally結(jié)構(gòu)下finally塊可能不執(zhí)行的情況,并分析了JVM層面的原理,文章列出了6種特殊情況,下面就來詳細(xì)的介紹一下2026-05-05
spring?boot只需兩步優(yōu)雅整合activiti示例解析
這篇文章主要主要來教大家spring?boot優(yōu)雅整合activiti只需兩步就可完成測操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步2022-03-03
IntelliJ IDEA 2020.2 配置大全詳細(xì)圖文教程(更新中)
這篇文章主要介紹了IntelliJ IDEA 2020.2 配置大全(更新中),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Docker搭建前端Java的開發(fā)環(huán)境詳解
相信每個(gè)人入職第一天就是搭建本地開發(fā)環(huán)境,因?yàn)槲宜居玫氖莏ava,看見了多年不見的eclipse的圖標(biāo)出現(xiàn)我的電腦上,我是難過的。后來知道并不是我一個(gè)人有此感受。這篇文章是為了解決前后端開發(fā)沒有徹底分離的坑,詳細(xì)的給大家介紹了利用Docker搭建前端Java的開發(fā)環(huán)境。2016-10-10
Java斷點(diǎn)續(xù)傳(文件分塊)完整實(shí)現(xiàn)步驟
這篇文章主要介紹了Java斷點(diǎn)續(xù)傳(文件分塊)完整實(shí)現(xiàn)步驟,?斷點(diǎn)續(xù)傳通過分塊傳輸大文件,中斷后可續(xù)傳未完成部分,服務(wù)端合并分塊,避免重復(fù)上傳,提升用戶體驗(yàn)并節(jié)省網(wǎng)絡(luò)資源,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-05-05
Spring?Boot使用線程池處理上萬條數(shù)據(jù)插入功能
這篇文章主要介紹了Spring?Boot使用線程池處理上萬條數(shù)據(jù)插入功能,使用步驟是先創(chuàng)建一個(gè)線程池的配置,讓Spring Boot加載,用來定義如何創(chuàng)建一個(gè)ThreadPoolTaskExecutor,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-08-08
SpringBoot中的ImportSelector類動(dòng)態(tài)加載bean詳解
這篇文章主要介紹了SpringBoot中的ImportSelector類動(dòng)態(tài)加載bean詳解,ImportSelector接口是spring中導(dǎo)入外部配置的核心接口,根據(jù)給定的條件(通常是一個(gè)或多個(gè)注釋屬性)判定要導(dǎo)入那個(gè)配置類,在spring自動(dòng)化配置和@EnableXXX中都有它的存在,需要的朋友可以參考下2024-01-01

