Java秒杀简单设计四:service层设计

接上一篇 https://www.cnblogs.com/taiguyiba/p/9829191.html  封装了系统传递的数据类和异常类

本文继续设计service层设计:

1.SeckillService.java 

package com.seckill.service;

import java.util.List;

import com.seckill.dto.Exposer;
import com.seckill.dto.SeckillExecution;
import com.seckill.entity.Seckill;
import com.seckill.exception.RepeatKillException;
import com.seckill.exception.SeckillCloseException;
import com.seckill.exception.SeckillException;

/**
 * 三个方面:1.方法定义的粒度,参数,返回类型(return ,类型/异常)
 * @author kangjie
 *
 */
public interface SeckillService {

    /**
     * 
     * 查询所有秒杀记录
     * @return
     */
    List <Seckill> getSeckillList();
    /**
     * 
     * 查询单个秒杀记录
     * @param seckillId
     * @return
     */
    Seckill getById(long seckillId);
    /**
     * 秒杀开启时输出秒杀接口地址 否则输出系统时间和秒杀时间
     * @param seckillId
     */
    Exposer exportSeckillUrl(long seckillId);

        //执行秒杀操作
    SeckillExecution excuteSeckill(long seckillId,long userPhone,String md5) 
                throws RepeatKillException,SeckillCloseException,SeckillException; 

    //执行秒杀操作by存储过程
    SeckillExecution excuteSeckillProcedure(long seckillId,long userPhone,String md5);
}

 2. SeckillServiceImpl

 秒杀事务控制,在函数中如果更新出现问题,就会抛出异常,进行事务回滚。

package com.seckill.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
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 com.seckill.dao.SeckillDao;
import com.seckill.dao.SuccessKilledDao;
import com.seckill.dao.cache.RedisDao;
import com.seckill.dto.Exposer;
import com.seckill.dto.SeckillExecution;
import com.seckill.entity.Seckill;
import com.seckill.entity.SuccessKilled;
import com.seckill.enums.SeckillStateEnum;
import com.seckill.exception.RepeatKillException;
import com.seckill.exception.SeckillCloseException;
import com.seckill.exception.SeckillException;
import com.seckill.service.SeckillService;

@Service
public class SeckillServiceImpl implements SeckillService {

    private Logger logger=LoggerFactory.getLogger(this.getClass());
    
    @Autowired
    private SeckillDao seckillDao;
    @Autowired
    private SuccessKilledDao successKilledDao;
    @Autowired
    private RedisDao redisDao;
    //md5盐值,用于混淆md5
    private final String salt = "!@#!@#!@#$ASDFASDFzxcv_|+)+)((";
    
    @Override
    public List<Seckill> getSeckillList() {
        // TODO Auto-generated method stub
        return seckillDao.queryAll(0, 4);
    }

    @Override
    public Seckill getById(long seckillId) {
        // TODO Auto-generated method stub
         return seckillDao.queryById(seckillId);
    }

    @Override
    public Exposer exportSeckillUrl(long seckillId) {
        // TODO Auto-generated method stub
        //访问redis:缓存优化,超时的基础上维护一致性
        Seckill seckill = redisDao.getSeckill(seckillId);
        if(seckill == null) {
            //访问数据库
            seckill = seckillDao.queryById(seckillId);
            if(seckill == null) {
                return new Exposer(false, seckillId);
            }else {
                logger.error("放入redis中: " + seckill.toString());
                redisDao.putSeckill(seckill);
            }
        } 
        Date startTime = seckill.getStartTime();
        Date endTime = seckill.getEndTime();
        Date nowTime = new Date();
        if(nowTime.getTime() > endTime.getTime() 
                ||nowTime.getTime() < startTime.getTime()) {
            return new Exposer(false, nowTime.getTime(), startTime.getTime(), endTime.getTime(),seckillId);
        }
        String md5 = getMD5(seckillId);
        return new Exposer(true, md5, seckillId);
    
//        return null;
    }
    private String getMD5(long seckillId) {
        String base = seckillId + "/" + salt;
        String md5 =  DigestUtils.md5DigestAsHex(base.getBytes());
        return md5;
    }

    @Override
    @Transactional
    public SeckillExecution excuteSeckill(long seckillId, long userPhone, String md5)
            throws RepeatKillException, SeckillCloseException, SeckillException {
        // TODO Auto-generated method stub
        if(md5 == null || !md5.equals(getMD5(seckillId))) {
            throw new SeckillException("seckill data rewirte");
        }
        try {

            int insertCount = successKilledDao.insertSuccessKilled(seckillId, userPhone);
            if (insertCount <= 0) {
                // 重复秒杀
                throw new RepeatKillException("repeat seckill");
            } else {
                int updateCount = seckillDao.reduceNumber(seckillId, new Date());
                if (updateCount <= 0) {
                    throw new SeckillCloseException("seckill closed");
                } else {
                    // 秒杀成功
                    SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
                    return new SeckillExecution(seckillId,SeckillStateEnum.SUCCESSD, successKilled);
                }

            }
        } catch (RepeatKillException e) {
            // TODO: handle exception
            logger.error(e.getMessage(),e);
            throw new RepeatKillException("repeat seckill");
        }catch (SeckillCloseException e) {
            // TODO: handle exception
            logger.error(e.getMessage(),e);
            throw new SeckillCloseException("seckill closed");
        }catch (Exception e) {
            logger.error(e.getMessage(), e);;
            throw new SeckillException("Inner error: " + e.getMessage());
        }
        
    }

    @Override
    public SeckillExecution excuteSeckillProcedure(long seckillId, long userPhone, String md5){
        // TODO Auto-generated method stub
        if(md5 == null || !md5.equals(getMD5(seckillId))) {
            return new SeckillExecution(seckillId,SeckillStateEnum.DATA_REWRITE);
        }
        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);
        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.SUCCESSD,sk);
            }else {
                return new SeckillExecution(seckillId, SeckillStateEnum.stateOf(result));
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            logger.error(e.getMessage(),e);
            return new SeckillExecution(seckillId, SeckillStateEnum.INNER_ERROR);
        }
    }

}

 

猜你喜欢

转载自www.cnblogs.com/taiguyiba/p/9829930.html