• 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);
            }
        }
    
    }

     

  • 相关阅读:
    安装Joomla!3
    keepalived + lvs
    systemd 服务介绍
    lvs 进阶 第二章
    lvs 初始 第一章
    iptables 最终 第四章
    bind 笔记
    iptables 扩展匹配 第三章
    iptables 认识 第二章
    iptables 初见 第一章
  • 原文地址:https://www.cnblogs.com/taiguyiba/p/9829930.html
Copyright © 2020-2023  润新知