java+mysql实现商品抢购功能

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

java+mysql实现商品抢购功能
我们希望有⼈购买时检查商品数量是否⾜够,如果库存有剩余那么就让⽤户购买成功,之后变更库存,假如⽤户排队挨个购买这样当然没有问题。

可是实际情况下,可能是⽤户多个⽤户同时来购买,同时检查库存,这是可能库存仅够其中⼀⼈购买,但是由于库存还没减掉,就会出现⼏个⼈都购买成功,然后库存减为负数出现超卖的情况。

这在⼤量⽤户在同⼀时间点同时购买时极可能出现。

于是我们调整⼀下顺序,有⽤户购买时我们先减掉库存,那你肯定要问,怎么减?库存不够⼀个⼈的时候也减?
我们假设每份商品有⼀个唯⼀的购买码(开始抢购前预先⽣成),⽤户抢到购买码的数量即他买到的份数,那么有⽤户购买时我们第⼀步就是给幸运码的状态由有效更改为⽆效,并为其标记上其购买者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();
mit();
}
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;
}
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

相关文档
最新文档