java+mysql實(shí)現(xiàn)商品搶購功能
我們希望有人購買時(shí)檢查商品數(shù)量是否足夠,如果庫存有剩余那么就讓用戶購買成功,之后變更庫存,假如用戶排隊(duì)挨個(gè)購買這樣當(dāng)然沒有問題。
可是實(shí)際情況下,可能是用戶多個(gè)用戶同時(shí)來購買,同時(shí)檢查庫存,這是可能庫存僅夠其中一人購買,但是由于庫存還沒減掉,就會(huì)出現(xiàn)幾個(gè)人都購買成功,然后庫存減為負(fù)數(shù)出現(xiàn)超賣的情況。這在大量用戶在同一時(shí)間點(diǎn)同時(shí)購買時(shí)極可能出現(xiàn)。
于是我們調(diào)整一下順序,有用戶購買時(shí)我們先減掉庫存,那你肯定要問,怎么減?庫存不夠一個(gè)人的時(shí)候也減?
我們假設(shè)每份商品有一個(gè)唯一的購買碼(開始搶購前預(yù)先生成),用戶搶到購買碼的數(shù)量即他買到的份數(shù),那么有用戶購買時(shí)我們第一步就是給幸運(yùn)碼的狀態(tài)由有效更改為無效,并為其標(biāo)記上其購買者ID
這樣其實(shí)mysql會(huì)給我們一個(gè)返回結(jié)果,叫做影響行數(shù),就是說這條語句更新影響了多少行的數(shù)據(jù),這個(gè)影響行數(shù)就是他實(shí)際購買到的商品份數(shù),如果影響行數(shù)為0,就說明一份也沒購買成功,也就意味著商品已經(jīng)搶購?fù)瓿闪恕?/p>
java實(shí)現(xiàn):
/**
* 生成商品的購買碼<大量數(shù)據(jù)插入>
*
* @param goodsIssue
* @author Nifury
*/
public void insertLotteryNumbers(GoodsIssue goodsIssue) {
String prefix = "INSERT INTO `lottery_number` (`goods_id`, `periods`,`luck_number`, `create_time`, `status`, `issue_id` ) VALUES \n";
Timestamp now = new Timestamp(System.currentTimeMillis());
Connection con = null;
try {
con = jdbcTemplate.getDataSource().getConnection();
con.setAutoCommit(false);
PreparedStatement pst = con.prepareStatement("");
Long total = goodsIssue.getTotalShare();// 總?cè)舜?
for (int i = 0; i < total; i += 10000) {// 1萬條提交一次
StringBuffer suffix = new StringBuffer();
List<Integer> numbers = new ArrayList<Integer>();
for (int j = 0; j < 10000 && i+j < total; j++) {
numbers.add(10000001 + i + j);
}
Collections.shuffle(numbers);//打亂幸運(yùn)碼
for (int n = 0,length = numbers.size(); n < length; n++) {
suffix.append("(" + goodsIssue.getGoodsId() + ","
+ goodsIssue.getPeriods() + ","
+ numbers.get(n) + ",'" + now.toString() + "',"
+ 1 + "," + goodsIssue.getIssueId() + ")\n,");
}
// 構(gòu)建完整sql
String sql = prefix + suffix.substring(0, suffix.length() - 2);
pst.addBatch(sql);
pst.executeBatch();
con.commit();
}
con.setAutoCommit(true);// 還原
pst.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
try {// 事務(wù)回滾
con.rollback();
con.setAutoCommit(true);
con.close();
} catch (SQLException e1) {
e1.printStackTrace();
}// 還原
}
}
分配購買碼(我們的業(yè)務(wù)需要給購買用戶展示購買碼,所以有返回)
/**
* 通過商品issue_id(每期每個(gè)商品有唯一issue_id)來隨機(jī)獲取購買碼(使用的購買碼會(huì)設(shè)為失效狀態(tài))
* @param issueId
* @param amount 需要獲取的購買碼的數(shù)量
* @param userId
* @return LotteryNumber對(duì)象列表
* @author Nifury 2016-7-22
*/
public List<LotteryNumber> queryByNewIssueId2(Long issueId, Long amount,Long userId) {
List<LotteryNumber> numberList = new ArrayList<LotteryNumber>();
try {
long currentTime=System.currentTimeMillis();
String updateUserId = "UPDATE `lottery_number` SET `status` = 0,`user_id` = ?,`current_time`= ? WHERE `issue_id` = ? AND `status`=1 LIMIT ? ";
int rownum=jdbcTemplate.update(updateUserId, userId, currentTime, issueId, amount );
if(rownum>0){//還有剩余有效購買碼
Object[] buyargs={issueId, userId ,currentTime};
numberList = jdbcTemplate.query(QUERY + " WHERE `issue_id` = ? AND `status` = 0 AND `user_id` = ? AND `current_time`= ?",
buyargs, LotteryNumberMapper);
}
} catch (DeadlockLoserDataAccessException e) {
System.out.println("----分配購買碼出現(xiàn)死鎖,用戶分得0個(gè)購買碼-----");
}
return numberList;
}
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- JavaWeb實(shí)現(xiàn)簡單查詢商品功能
- Java使用策略模式解決商場促銷商品問題示例
- java使用hadoop實(shí)現(xiàn)關(guān)聯(lián)商品統(tǒng)計(jì)
- JAVAEE model1模型實(shí)現(xiàn)商品瀏覽記錄(去除重復(fù)的瀏覽記錄)(一)
- java實(shí)現(xiàn)商品管理系統(tǒng)
- java實(shí)現(xiàn)超市商品庫存管理平臺(tái)
- java實(shí)現(xiàn)商品信息管理系統(tǒng)
- Java基于JDBC實(shí)現(xiàn)事務(wù),銀行轉(zhuǎn)賬及貨物進(jìn)出庫功能示例
- Java實(shí)現(xiàn)商品的查找、添加、出庫、入庫操作完整案例
相關(guān)文章
Java設(shè)計(jì)模式之代理模式與@Async異步注解失效的解決
代理模式是Java常見的設(shè)計(jì)模式之一。所謂代理模式是指客戶端并不直接調(diào)用實(shí)際的對(duì)象,而是通過調(diào)用代理,來間接的調(diào)用實(shí)際的對(duì)象2022-07-07
iOS socket網(wǎng)絡(luò)編程實(shí)例詳解
socket是一個(gè)針對(duì)TCP和UDP編程的接口,你可以借助它建立TCP連接等。這篇文章主要介紹了iOS socket網(wǎng)絡(luò)編程 ,需要的朋友可以參考下2017-03-03
SpringBoot獲取不到用戶真實(shí)IP的解決方法
最近遇到個(gè)問題,項(xiàng)目部署后發(fā)現(xiàn)服務(wù)端無法獲取到客戶端真實(shí)的IP地址,本文就來介紹一下這個(gè)問題的解決方法,感興趣的可以了解一下2023-08-08
Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之樹
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之樹,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java數(shù)據(jù)結(jié)構(gòu)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-05-05
springboot2.0+elasticsearch5.5+rabbitmq搭建搜索服務(wù)的坑
這篇文章主要介紹了springboot2.0+elasticsearch5.5+rabbitmq搭建搜索服務(wù)的坑,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06
Java Spring數(shù)據(jù)單元配置過程解析
這篇文章主要介紹了Java Spring數(shù)據(jù)單元配置過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12
Java Socket編程實(shí)例(三)- TCP服務(wù)端線程池
這篇文章主要講解Java Socket編程中TCP服務(wù)端線程池的實(shí)例,希望能給大家做一個(gè)參考。2016-06-06
Spring IOC和DI實(shí)現(xiàn)原理及實(shí)例解析
這篇文章主要介紹了Spring IOC和DI實(shí)現(xiàn)原理及實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
關(guān)于JwtToken使用-重點(diǎn)看一下過期時(shí)間
這篇文章主要介紹了關(guān)于JwtToken使用-重點(diǎn)看一下過期時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
一篇文章帶你學(xué)習(xí)Mybatis-Plus(新手入門)
這篇文章主要介紹了MyBatis-Plus 快速入門案例(小白教程),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-08-08

