秒杀项目-service接口设计与实现

 从这里开始

接口设计 ​​​​​​​

package org.seckill.service;

import org.seckill.dto.Exposer;
import org.seckill.dto.SeckillExecution;
import org.seckill.entity.Seckill;
import org.seckill.exception.RepeatKillException;
import org.seckill.exception.SeckillColseException;
import org.seckill.exception.SeckillException;

import java.util.List;

/**
 * 业务接口:站在使用者角度设计接口
 * 三个方面:方法定义粒度,参数,返回类型
 */
public interface SeckillService {

    /**
     * 查询所有秒杀记录
     * @return
     */
    List<Seckill> getSeckillList();

    /**
     * 根据id查询秒杀记录
     * @param seckillId
     * @return
     */
    Seckill getSeckillById(long seckillId);

    /**
     * 秒杀开始时输出秒杀接口地址
     * 否则输出系统时间和秒杀时间
     * @param seckillId
     */
    Exposer exportSeckillUrl(long seckillId);


    /**
     * 执行秒杀
     * @param seckillId
     * @param userPhone
     * @param md5
     */
    SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
        throws SeckillException, RepeatKillException, SeckillColseException;

    /**
     * 使用存储过程优化
     */
//    SeckillExecution executeSeckillProcedure(long seckillId, long userPhone, String md5);


}

接口实现

package org.seckill.service.serviceImpl;

import org.seckill.dao.SeckillDAO;
import org.seckill.dao.SuccessKilledDAO;
import org.seckill.dto.Exposer;
import org.seckill.dto.SeckillExecution;
import org.seckill.entity.Seckill;
import org.seckill.entity.SuccessKilled;
import org.seckill.enums.SeckillStateEnum;
import org.seckill.exception.RepeatKillException;
import org.seckill.exception.SeckillColseException;
import org.seckill.exception.SeckillException;
import org.seckill.service.SeckillService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.List;

@Service
public class SeckillServiceImpl implements SeckillService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

//   @Autowired
//   private RedisDAO redisDAO;

    @Autowired
    private SeckillDAO seckillDAO;

    @Autowired
    private SuccessKilledDAO successKilledDAO;

    //盐值
    private final String slat = "akdjtoiakgj#$%%ak45u09uirjg934374t8*$*%";

    @Override
    public List<Seckill> getSeckillList() {
        //这里不做分页 简单测试 4个
        return seckillDAO.queryAll(0, 4);
    }

    @Override
    public Seckill getSeckillById(long seckillId) {
        return seckillDAO.queryById(seckillId);
    }

    @Override
    public Exposer exportSeckillUrl(long seckillId) {


       //优化点:缓存优化
        /**
         * get from cache if null
         * get db
         * put cache
         * 单独抽取 RedisDAO
         */
//        Seckill seckill = redisDAO.getSeckill(seckillId);
//        if(seckill == null){
//            seckill = seckillDAO.queryById(seckillId);
//            if(seckill != null){
//                //放入redis
//                String result = redisDAO.putSeckill(seckill);
//            }else{
//                return new Exposer(false,seckillId);
//            }
//        }


        Seckill seckill = seckillDAO.queryById(seckillId);
        if (seckill == null) {
            return new Exposer(false, seckillId);
        }
        Date startTime = seckill.getStartTime();
        Date endTime = seckill.getEndTime();
        Date nowTime = new Date();
        if (nowTime.getTime() < startTime.getTime()
                || nowTime.getTime() > endTime.getTime()) {
            return new Exposer(false, seckillId, nowTime.getTime(), startTime.getTime(), endTime.getTime());
        }
        //md5加密 不可逆
        String md5 = getMD5(seckillId);
        return new Exposer(true, md5, seckillId);
    }

    //生成MD5
    private String getMD5(long seckillId) {
        String base = seckillId + "/" + slat;
        String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
        return md5;
    }

    @Override
    @Transactional
    /**
     * 使用注解声明事务优点
     * 明确标注事务方法 清晰
     * 保证事务方法的执行时间尽可能的短,不要穿插其它的网络操作或者剥离到事务方法外部
     * 不是所有的方法都需要事务只读操作 或只有一条修改操作
     */
    public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5) throws SeckillException, RepeatKillException, SeckillColseException {
        if (md5 == null || !md5.equals(getMD5(seckillId))) {
            throw new SeckillException("seckill data rewrite");
        }
        //执行秒杀逻辑 减库存+ 记录购买行为
        Date nowTime = new Date();
        try {
            int updateCount = seckillDAO.reduceNumber(seckillId, nowTime);
            //减库存
            if (updateCount <= 0) {
                //没有更新到记录
                throw new SeckillColseException("seckill is closed");
            } else {
                //成功 记录购买行为
                int insertCount = successKilledDAO.insertSuccessKilled(seckillId, userPhone);
                //唯一:seckillId,userPhone
                if (insertCount <= 0) {
                    //重复秒杀
                    throw new RepeatKillException("seckill repeated");
                } else {
                    //秒杀成功
                    SuccessKilled successKilled = successKilledDAO.queryByIdWithSeckill(seckillId, userPhone);
                    return new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS,successKilled);
                }
            }

        }catch (SeckillColseException e1){
            throw e1;
        }catch (RepeatKillException e2){
            throw e2;
        }catch (Exception e) {
            logger.error(e.getMessage(), e);
            //所有编译期异常 转化为运行期异常 spring只接受运行时异常
            throw new SeckillException("seckill innwe error:"+e.getMessage());
        }
    }

    /**
     * 使用存储过程优化
     */
//    @Override
//    public SeckillExecution executeSeckillProcedure(long seckillId, long userPhone, String md5) {
//       if(md5 == null || !md5.equals(getMD5(seckillId))){
//           return new SeckillExecution(seckillId,SeckillStateEnum.DATA_REWRIRE);
//       }
//        Date killTime = new Date();
//       Map<String,Object> map = new HashMap<String,Object>();
//       map.put("seckillId",seckillId);
//       map.put("phone",userPhone);
//       map.put("killTime",killTime);
//       map.put("result",null);
//
//       //执行存储过程后result被赋值
//        try{
//             seckillDAO.killByProcedure(map);
//             //获取result
//            int result = MapUtils.getInteger(map,"result",-2);
//            if(result == 1){
//                SuccessKilled sk = successKilledDAO.queryByIdWithSeckill(seckillId, userPhone);
//                return new SeckillExecution(seckillId,SeckillStateEnum.SUCCESS);
//            }else{
//                return new SeckillExecution(seckillId,SeckillStateEnum.stateOf(result));
//            }
//        }catch (Exception e){
//            logger.error(e.getMessage(),e);
//            return new SeckillExecution(seckillId,SeckillStateEnum.INNER_ERROR);
//        }
//
//    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wonder4work

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值