[DAO编写之后的总结]

DAO层    -->    接口设计 + SQL编写

DAO拼接等逻辑    -->    统一在Service层完成

[Service层的接口设计]

1.接口设计原则:站在'使用者'的角度设计接口

2.方法定义粒度:从'使用者'的行为角度来思考-- 减库存+插入购买明细 --> 执行秒杀

3.参数:越简练越直接

4.返回类型:return 类型/Exception 返回类型要友好,使用DTO

  1. package org.azcode.service;
  2.  
  3. import org.azcode.dto.Exposer;
  4. import org.azcode.dto.SeckillExecution;
  5. import org.azcode.entity.Seckill;
  6. import org.azcode.exception.RepeatKillException;
  7. import org.azcode.exception.SeckillCloseException;
  8. import org.azcode.exception.SeckillException;
  9.  
  10. import java.util.List;
  11.  
  12. /**
  13. * Created by azcod on 2017/4/15.
  14. */
  15. public interface SeckillService {
  16.  
  17. /**
  18. * 查询所有的秒杀记录
  19. * @return
  20. */
  21. List<Seckill> getSeckillList();
  22.  
  23. /**
  24. * 根据id查询单个秒杀记录
  25. * @param seckillId
  26. * @return
  27. */
  28. Seckill getById(long seckillId);
  29.  
  30. /**
  31. * 秒杀开启时输出秒杀接口地址,
  32. * 否则输出系统时间和秒杀时间
  33. * @param seckillId
  34. * @return Exposer
  35. */
  36. Exposer exportSeckillUrl(long seckillId);
  37.  
  38. /**
  39. * 执行秒杀操作
  40. * @param seckillId
  41. * @param userPhone
  42. * @param md5
  43. * @return SeckillExecution
  44. */
  45. SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
  46. throws SeckillException,RepeatKillException,SeckillCloseException;
  47. }

[Service接口实现编码]

1.防止数据篡改的措施,使用MD5给数据加密

2.具体业务逻辑的编码,对异常的处理

3.异常的多重catch,将编译期异常转换为运行期异常

4.使用枚举表述常量数据字典

  1. package org.azcode.service.impl;
  2.  
  3. import org.azcode.dao.SeckillDao;
  4. import org.azcode.dao.SuccessKilledDao;
  5. import org.azcode.dto.Exposer;
  6. import org.azcode.dto.SeckillExecution;
  7. import org.azcode.entity.Seckill;
  8. import org.azcode.entity.SuccessKilled;
  9. import org.azcode.enums.SeckillStateEnum;
  10. import org.azcode.exception.RepeatKillException;
  11. import org.azcode.exception.SeckillCloseException;
  12. import org.azcode.exception.SeckillException;
  13. import org.azcode.service.SeckillService;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. import org.springframework.util.DigestUtils;
  17.  
  18. import java.util.Date;
  19. import java.util.List;
  20.  
  21. /**
  22. * Created by azcod on 2017/4/15.
  23. */
  24. public class SeckillServiceImpl implements SeckillService {
  25.  
  26. private Logger logger = LoggerFactory.getLogger(this.getClass());
  27.  
  28. private SeckillDao seckillDao;
  29.  
  30. private SuccessKilledDao successKilledDao;
  31.  
  32. //MD5盐值字符串,用于混淆MD5
  33. private final String slat = "r#^*T*(&F)HHU!&@T#456465";
  34.  
  35. public List<Seckill> getSeckillList() {
  36. return seckillDao.queryAll(0, 4);
  37. }
  38.  
  39. public Seckill getById(long seckillId) {
  40. return seckillDao.queryById(seckillId);
  41. }
  42.  
  43. public Exposer exportSeckillUrl(long seckillId) {
  44. Seckill seckill = seckillDao.queryById(seckillId);
  45. //step1:判断秒杀产品是否存在
  46. if (seckill == null) {
  47. return new Exposer(false, seckillId);
  48. }
  49. //step2:判断秒杀是否开启
  50. Date startTime = seckill.getStartTime();
  51. Date endTime = seckill.getEndTime();
  52. Date nowTime = new Date();
  53. if (nowTime.getTime() < startTime.getTime()
  54. || nowTime.getTime() > endTime.getTime()) {
  55. return new Exposer(false, seckillId,
  56. nowTime.getTime(), startTime.getTime(), endTime.getTime());
  57. }
  58. //MD5:一种转换特定字符串的过程,不可逆
  59. String md5 = getMD5(seckillId);
  60. return new Exposer(true, md5, seckillId);
  61. }
  62.  
  63. public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
  64. throws SeckillException, RepeatKillException, SeckillCloseException {
  65. //step1:校验是否篡改秒杀数据
  66. if (md5 == null || !md5.equals(getMD5(seckillId))) {
  67. throw new SeckillException("seckill data rewrite");
  68. }
  69. //step2:秒杀逻辑-减库存+插入购买明细
  70. Date nowTime = new Date();
  71. // 异常捕获的IDEA快捷键:包选代码块后->ctrl+alt+t
  72. try {
  73. //减库存
  74. int updateCount = seckillDao.reduceNumber(seckillId, nowTime);
  75. if (updateCount <= 0) {
  76. //秒杀结束
  77. throw new SeckillCloseException("seckill is closed");
  78. } else {
  79. //插入购买明细
  80. int insertCount = successKilledDao.insertSuccessKilled(seckillId, userPhone);
  81. if (insertCount <= 0) {
  82. //重复秒杀
  83. throw new RepeatKillException("seckill repeated");
  84. } else {
  85. //秒杀成功
  86. SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
  87. return new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS, successKilled);
  88. }
  89. }
  90. } catch (SeckillCloseException e1) {
  91. throw e1;
  92. } catch (RepeatKillException e2) {
  93. throw e2;
  94. } catch (Exception e) {
  95. logger.error(e.getMessage(), e);
  96. //所有编译期异常转换为运行期异常,Spring声明式事务只支持运行期异常的回滚
  97. //转换的目的是为了出现编译期异常时,rollback回滚
  98. throw new SeckillException("seckill inner error" + e.getMessage());
  99. }
  100. }
  101.  
  102. /**
  103. * 生成MD5的通用方法
  104. *
  105. * @param seckillId
  106. * @return
  107. */
  108. private String getMD5(long seckillId) {
  109. String base = seckillId + slat;
  110. String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
  111. return md5;
  112. }
  113. }
  1. package org.azcode.enums;
  2.  
  3. /**
  4. * 使用枚举表述常量数据字典
  5. * Created by azcod on 2017/4/15.
  6. */
  7. public enum SeckillStateEnum {
  8. SUCCESS(1, "秒杀成功"),
  9. END(0, "秒杀结束"),
  10. REPEAT_KILL(-1, "重复秒杀"),
  11. INNER_ERROR(-2, "系统异常"),
  12. DATA_REWRITE(-3, "数据篡改");
  13.  
  14. private int state;
  15.  
  16. private String stateInfo;
  17.  
  18. SeckillStateEnum(int state, String stateInfo) {
  19. this.state = state;
  20. this.stateInfo = stateInfo;
  21. }
  22.  
  23. public int getState() {
  24. return state;
  25. }
  26.  
  27. public String getStateInfo() {
  28. return stateInfo;
  29. }
  30.  
  31. public static SeckillStateEnum stateOf(int index) {
  32. for (SeckillStateEnum stateEnum : values()) {
  33. if (stateEnum.getState() == index) {
  34. return stateEnum;
  35. }
  36. }
  37. return null;
  38. }
  39. }

高并发秒杀系统--Service接口设计与实现的更多相关文章

  1. 高并发秒杀系统--Service事务管理与继承测试

    [Spring IoC的类型及应用场景]  [Spring事务使用方式] [Spring事务的特性] [Spring事务回滚的理解] [Service声明式事务的配置] 1.配置事务管理器 2.配置基 ...

  2. 【高并发】Redis如何助力高并发秒杀系统,看完这篇我彻底懂了!!

    写在前面 之前,我们在<[高并发]高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!>一文中,详细讲解了高并发秒杀系统的架构设计,其中,我们介绍了可以使用Redis存储秒杀商品的库存数量.很 ...

  3. Java高并发秒杀系统API之SSM框架集成swagger与AdminLTE

    初衷与整理描述 Java高并发秒杀系统API是来源于网上教程的一个Java项目,也是我接触Java的第一个项目.本来是一枚c#码农,公司计划部分业务转java,于是我利用业务时间自学Java才有了本文 ...

  4. Java高并发秒杀系统【观后总结】

    项目简介 在慕课网上发现了一个JavaWeb项目,内容讲的是高并发秒杀,觉得挺有意思的,就进去学习了一番. 记录在该项目中学到了什么玩意.. 该项目源码对应的gitHub地址(由观看其视频的人编写,并 ...

  5. 高并发秒杀系统--mybatis整合技巧

    mybatis实现DAO接口编码技巧 1.XML文件通过namespace命名空间关联接口类 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD ...

  6. 高并发秒杀系统--junit测试类与SpringIoc容器的整合

    1.原理是在Junit启动时加载SpringIoC容器 2.SpringIoC容器要根据Spring的配置文件加载 [示例代码] package org.azcode.dao; import org. ...

  7. 高并发秒杀系统方案(分布式session)

    编程要有一个习惯:做参数校验 所谓的分布式session:就是用redis统一管理session. 我们这里的思路是:把token写入cookie中,客户端在随后的访问中携带cookie,服务端就能根 ...

  8. 高并发秒杀系统--SpringMVC整合

    [SpringMVC运行流程] [Handler注解映射技巧] [请求方法的细节处理] 1.如何处理请求参数和方法参数的绑定? 2.如何限制方法接收的请求方式? 3.如何进行请求转发和重定向? 4.如 ...

  9. 高并发秒杀系统方案(JSR303参数校验)

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring- ...

随机推荐

  1. Arduino内部网页代理,网页穿透,公网访问Arduino内部网页

    #include <ESP8266WiFi.h> const char* id     = "id";  //http://www.mcunode.com/proxy/ ...

  2. winserver的consul部署实践与.net core客户端使用(附demo源码)

    winserver的consul部署实践与.net core客户端使用(附demo源码)   前言 随着微服务兴起,服务的管理显得极其重要.都知道微服务就是”拆“,把臃肿的单块应用,拆分成多个轻量级的 ...

  3. (十一)Updating Documents

    In addition to being able to index and replace documents, we can also update documents. Note though ...

  4. 数据类型:list列表[]、元祖tuple()、dict字典{}

    List 列表[] 可变的 lst = [1,2,3,4] #改 lst[(元素下标)] = '需要修改的' #通过下表修改 lst[下标:下标] = '需要修改的' #通过范围修改 #加 lst.a ...

  5. Swagger 配置

    放行 , 不拦截. @Configuration open class MyWebMvcConfig : WebMvcConfigurationSupport() { override fun add ...

  6. Openstack基础环境交换机常用配置(CISCO 3750G为例)

    NOTE: 用户模式提示符为:cisco> 特权模式提示符为:cisco# 全局配置模式提示符为:cisco(config)# 端口模式提示符为:cisco(config-if)# 基础操作   ...

  7. VS2010创建MVC4项目提示错误: 此模板尝试加载组件程序集 “NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral,

    在安装VS2010时没有安装MVC4,于是后面自己下载安装了(居然还要安装VS2010 SP1补丁包).装完后新建MVC项目时却提示: 错误: 此模板尝试加载组件程序集 “NuGet.VisualSt ...

  8. [转帖]Ansible批量远程管理Windows主机(部署与配置)

    2018-09-12 12:04:42 https://blog.51cto.com/7424593/2174156 一.测试环境介绍 Ansible管理主机: 系统:   CentOS6.8 IP ...

  9. Win10 登陆密码不正确(安全模式仍然启动不了)

    今天朋友重启Win10后,登陆密码显示不正确,是用了很多方法都不行 然后就瞎捣鼓就进去 进入BIOS将启动模式调为USB模式 重启启动不了后 再改回系统启动 就进去了(好神奇)

  10. vue-cli的跨域配置(自己总结)