我們希望有人購買時檢查商品數量是否足夠,如果庫存有剩餘那麼就讓用戶購買成功,之後變更庫存,假如用戶排隊挨個購買這樣當然沒有問題。
可是實際情況下,可能是用戶多個用戶同時來購買,同時檢查庫存,這是可能庫存僅夠其中一人購買,但是由於庫存還沒減掉,就會出現幾個人都購買成功,然後庫存減為負數出現超賣的情況。這在大量用戶在同一時間點同時購買時極可能出現。
於是我們調整一下順序,有用戶購買時我們先減掉庫存,那你肯定要問,怎麼減?庫存不夠一個人的時候也減?
我們假設每份商品有一個唯一的購買碼(開始搶購前預先生成),用戶搶到購買碼的數量即他買到的份數,那麼有用戶購買時我們第一步就是給幸運碼的狀態由有效更改為無效,並為其標記上其購買者ID
複製代碼代碼如下:"UPDATE `lottery_number` SET `status` = 失效狀態,`user_id` = 購買者用戶Id,`current_time`= 時間戳WHERE `goods_id` = 搶購的商品ID AND `status`=有效狀態LIMIT 購買份數";
這樣其實mysql會給我們一個返回結果,叫做影響行數,就是說這條語句更新影響了多少行的數據,這個影響行數就是他實際購買到的商品份數,如果影響行數為0,就說明一份也沒購買成功,也就意味著商品已經搶購完成了。
java實現:
/** * 生成商品的購買碼<大量數據插入> * * @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();// 總人次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);//打亂幸運碼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,"); } // 構建完整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 {// 事務回滾con.rollback(); con.setAutoCommit(true); con.close(); } catch (SQLException e1) { e1.printStackTrace(); }// 還原}}分配購買碼(我們的業務需要給購買用戶展示購買碼,所以有返回)
/** * 通過商品issue_id(每期每個商品有唯一issue_id)來隨機獲取購買碼(使用的購買碼會設為失效狀態) * @param issueId * @param amount 需要獲取的購買碼的數量* @param userId * @return LotteryNumber對象列表* @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("----分配購買碼出現死鎖,用戶分得0個購買碼-----"); } return numberList;}以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。