您的位置:首页 > 编程语言 > Java开发

抽奖抢购算法改进版

2016-11-07 00:00 134 查看
由于之前的算法存在以下问题:
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 抽奖 抢购 算法