抽奖抢购算法改进版
2016-11-07 00:00
134 查看
由于之前的算法存在以下问题:
1)高并发存在锁问题
2)执行效率不高
因此将原算法拆分为抢购和抽奖两个方法
1)高并发存在锁问题
2)执行效率不高
因此将原算法拆分为抢购和抽奖两个方法
抽奖拆分为两个方法
/** * 抽奖算法(不保存) * @param actId * @param person * @param checkDate * @return ret=-1 没有抽奖数据;-3 其他错误;>=0 中奖productId; infoId=奖品ID * @throws SQLException */ public static AwardResult getAwardOnly(int actId, String person, boolean checkDate) throws SQLException{ AwardResult result = new AwardResult(); try{ String sql = "select t.id, t.product_id, t.odds from award_info t where t.act_id=? and t.state=0 "; if(checkDate){ sql = sql + " and t.start_Date <= sysdate and t.end_Date >= sysdate "; } List<Map<String,Object>> rows = JDBC.getRows2(sql, new Object[]{actId}); if(rows.isEmpty()){//没有抽奖数据 log.info("没有抽奖数据 actId={} person={} checkDate={}", actId, person, checkDate); result.ret = -1; return result; } int[][] temp = new int[rows.size()][3]; int sum = -1; for(int k = 0; k < rows.size(); k++){//设置奖品池 int odds = ((BigDecimal)rows.get(k).get("ODDS")).intValue(); sum++; temp[k][0] = sum; //起始值 sum = sum + odds; temp[k][1] = sum; //结束值 temp[k][2] = k; //rows index } //抽奖 Random random = new Random(); int r = random.nextInt(sum + 1); int j = 0; for(int k = 0; k < rows.size(); k++){ if(r >= temp[k][0] && r <= temp[k][1]){ j = k; break; } } result.infoId = ((BigDecimal)rows.get(temp[j][2]).get("ID")).intValue(); result.ret = ((BigDecimal)rows.get(temp[j][2]).get("PRODUCT_ID")).intValue(); if(isDebug){ BusinessLog.saveBusinessLog(actId, person, result.ret + ""); } return result; }catch(Exception e){ log.error("getAwardOnly exception", e); result.ret = -3; return result; } }
/** * 减少库存 * @param infoId * @return -2 奖品已抽完; -3 其他错误;>=0 中奖productId * @throws SQLException */ public static AwardResult reduceAwardInfo(int infoId, String person, boolean saveLog) throws SQLException{ Connection conn = JDBC.getConnection(); AwardResult result = new AwardResult(); try{ conn.setAutoCommit(false); //锁定获奖池 String sql = "select num, rest, act_id, product_id, product_name from award_info where id=? for update"; Map<String, Object> row = JDBC.getRow2(sql, new Object[]{infoId}, conn); int num = ((Number)row.get("NUM")).intValue(); int rest = ((Number)row.get("REST")).intValue(); int proId = ((Number)row.get("PRODUCT_ID")).intValue(); if(num > 0 && rest <= 0){//存量不足 log.info("奖品已清空 infoId={}", infoId); JDBC.commit(conn); result.ret = -2; return result; } if(num > 0){//奖品限量,扣减库存 sql = "update award_info set rest = rest - 1 where id=?"; JDBC.update2(sql, new Object[]{infoId}, conn); } if(saveLog){ //记录获奖名单 AwardLog log = new AwardLog(); log.setActId(((Number)row.get("ACT_ID")).intValue()); log.setNum(1); log.setPerson(person); log.setProductId(proId); log.setInfoId(infoId); log.setRemark((String)row.get("PRODUCT_NAME")); Number logId = log.save(conn); if(logId == null){ throw new SQLException("save award_log error"); } result.logId = logId.intValue(); } result.infoId = infoId; result.ret = proId; conn.commit(); return result; }catch(SQLException e){ conn.rollback(); log.error("reduceAwardInfo", e); result.ret = -3; return result; }finally{ JDBC.close(conn); } }
抢购
/** * 抢购 * @param actId * @param person * @param checkDate * @return ret=-1 没有抽奖数据;-2 奖品已抽完;-3 其他错误;>=0 中奖productId; infoId=奖品ID * @throws SQLException */ public static AwardResult grab(int actId, String person, int productId, boolean checkDate) throws SQLException{ AwardResult result = new AwardResult(); Connection conn = JDBC.getConnection(); try{ conn.setAutoCommit(false); String sql = "select t.id, t.product_id, t.num, t.rest, t.odds, t.product_name from award_info t where t.act_id=? and t.state=0 and t.product_id=? "; if(checkDate){ sql = sql + " and t.start_Date <= sysdate and t.end_Date >= sysdate "; } sql = sql + " for update"; List<Map<String,Object>> rows = JDBC.getRows2(sql, new Object[]{actId, productId}, conn); if(rows.isEmpty()){//没有抢购数据 log.info("没有抢购数据 actId={} person={} productId={} checkDate={}", actId, person, productId, checkDate); JDBC.rollback(conn); result.ret = -1; return result; } int num = ((Number)rows.get(0).get("NUM")).intValue(); int rest = ((Number)rows.get(0).get("REST")).intValue(); int infoId = ((Number)rows.get(0).get("ID")).intValue(); //存量不足 if(num > 0 && rest <= 0){ log.info("抢购奖品已清空 actId={} person={} productId={} checkDate={}", actId, person, productId, checkDate); JDBC.rollback(conn); result.ret = -2; return result; } //更新奖品记录 if(num > 0){//非不限量扣减库存 sql = "update award_info set rest = rest - 1 where id = ?"; JDBC.update2(sql, new Object[]{infoId}, conn); } //记录获奖名单 AwardLog log = new AwardLog(); log.setActId(actId); log.setNum(1); log.setPerson(person); log.setProductId(productId); log.setInfoId(infoId); log.setRemark((String)rows.get(0).get("PRODUCT_NAME")); Number logId = log.save(conn); if(logId == null){ throw new SQLException("save award_log error"); } result.logId = logId.intValue(); result.ret = productId; result.infoId = infoId; JDBC.commit(conn); return result; }catch(Exception e){ log.error("grab exception", e); JDBC.rollback(conn); result.ret = -3; return result; }finally{ JDBC.close(conn); } }
相关文章推荐
- Java抽奖抢购算法
- Java抽奖抢购算法
- PHP解决抢购、秒杀、抢楼、抽奖等阻塞式高并发库存防控超量的思路方法
- 旋转数组的最小数字(改进版算法)
- php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法
- php编写的抽奖程序中奖概率算法
- java抽奖算法
- 微信平台抽奖算法总结-再也不用怕奖品被提前抢光
- 幸运大转盘抽奖 抽奖算法 程序实现逻辑
- 通过概率实现抽奖的算法
- php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法
- php编写的抽奖程序中奖概率算法
- 排列组合算法之二: 01转换法_java改变后的c++改进版
- PHP+jQuery实现翻板抽奖(中奖概率算法)
- PHP抽奖算法程序代码分享
- 4类抽奖算法总结
- java抽奖算法
- 如何高效设计游戏——从抽奖模型到圆桌算法
- 面试题79:抽奖算法实现
- 一道关于抽奖的算法