mysql 抢购_java+mysql实现商品抢购功能
发布日期:2022-02-03 13:16:58 浏览次数:8 分类:技术文章

本文共 2910 字,大约阅读时间需要 9 分钟。

我们希望有人购买时检查商品数量是否足够,如果库存有剩余那么就让用户购买成功,之后变更库存,假如用户排队挨个购买这样当然没有问题。

可是实际情况下,可能是用户多个用户同时来购买,同时检查库存,这是可能库存仅够其中一人购买,但是由于库存还没减掉,就会出现几个人都购买成功,然后库存减为负数出现超卖的情况。这在大量用户在同一时间点同时购买时极可能出现。

于是我们调整一下顺序,有用户购买时我们先减掉库存,那你肯定要问,怎么减?库存不够一个人的时候也减?

我们假设每份商品有一个唯一的购买码(开始抢购前预先生成),用户抢到购买码的数量即他买到的份数,那么有用户购买时我们第一步就是给幸运码的状态由有效更改为无效,并为其标记上其购买者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 numbers = new ArrayList();

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 queryByNewIssueId2(Long issueId, Long amount,Long userId) {

List numberList = new ArrayList();

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;

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

转载地址:https://blog.csdn.net/weixin_34759094/article/details/113209162 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:linux mysql 随机密码_centos命令行安装mysql随机密码查看方法(遇到问题及其解决办法)...
下一篇:mysql中怎么查看从节点_MySQL中进行树状所有子节点的查询

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月04日 06时17分48秒