高并发秒杀系统--Service接口设计与实现
[DAO编写之后的总结]
DAO层 --> 接口设计 + SQL编写
DAO拼接等逻辑 --> 统一在Service层完成
[Service层的接口设计]
1.接口设计原则:站在'使用者'的角度设计接口
2.方法定义粒度:从'使用者'的行为角度来思考-- 减库存+插入购买明细 --> 执行秒杀
3.参数:越简练越直接
4.返回类型:return 类型/Exception 返回类型要友好,使用DTO
- package org.azcode.service;
- import org.azcode.dto.Exposer;
- import org.azcode.dto.SeckillExecution;
- import org.azcode.entity.Seckill;
- import org.azcode.exception.RepeatKillException;
- import org.azcode.exception.SeckillCloseException;
- import org.azcode.exception.SeckillException;
- import java.util.List;
- /**
- * Created by azcod on 2017/4/15.
- */
- public interface SeckillService {
- /**
- * 查询所有的秒杀记录
- * @return
- */
- List<Seckill> getSeckillList();
- /**
- * 根据id查询单个秒杀记录
- * @param seckillId
- * @return
- */
- Seckill getById(long seckillId);
- /**
- * 秒杀开启时输出秒杀接口地址,
- * 否则输出系统时间和秒杀时间
- * @param seckillId
- * @return Exposer
- */
- Exposer exportSeckillUrl(long seckillId);
- /**
- * 执行秒杀操作
- * @param seckillId
- * @param userPhone
- * @param md5
- * @return SeckillExecution
- */
- SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
- throws SeckillException,RepeatKillException,SeckillCloseException;
- }
[Service接口实现编码]
1.防止数据篡改的措施,使用MD5给数据加密
2.具体业务逻辑的编码,对异常的处理
3.异常的多重catch,将编译期异常转换为运行期异常
4.使用枚举表述常量数据字典
- package org.azcode.service.impl;
- import org.azcode.dao.SeckillDao;
- import org.azcode.dao.SuccessKilledDao;
- import org.azcode.dto.Exposer;
- import org.azcode.dto.SeckillExecution;
- import org.azcode.entity.Seckill;
- import org.azcode.entity.SuccessKilled;
- import org.azcode.enums.SeckillStateEnum;
- import org.azcode.exception.RepeatKillException;
- import org.azcode.exception.SeckillCloseException;
- import org.azcode.exception.SeckillException;
- import org.azcode.service.SeckillService;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.util.DigestUtils;
- import java.util.Date;
- import java.util.List;
- /**
- * Created by azcod on 2017/4/15.
- */
- public class SeckillServiceImpl implements SeckillService {
- private Logger logger = LoggerFactory.getLogger(this.getClass());
- private SeckillDao seckillDao;
- private SuccessKilledDao successKilledDao;
- //MD5盐值字符串,用于混淆MD5
- private final String slat = "r#^*T*(&F)HHU!&@T#456465";
- public List<Seckill> getSeckillList() {
- return seckillDao.queryAll(0, 4);
- }
- public Seckill getById(long seckillId) {
- return seckillDao.queryById(seckillId);
- }
- public Exposer exportSeckillUrl(long seckillId) {
- Seckill seckill = seckillDao.queryById(seckillId);
- //step1:判断秒杀产品是否存在
- if (seckill == null) {
- return new Exposer(false, seckillId);
- }
- //step2:判断秒杀是否开启
- 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);
- }
- public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
- throws SeckillException, RepeatKillException, SeckillCloseException {
- //step1:校验是否篡改秒杀数据
- if (md5 == null || !md5.equals(getMD5(seckillId))) {
- throw new SeckillException("seckill data rewrite");
- }
- //step2:秒杀逻辑-减库存+插入购买明细
- Date nowTime = new Date();
- // 异常捕获的IDEA快捷键:包选代码块后->ctrl+alt+t
- try {
- //减库存
- int updateCount = seckillDao.reduceNumber(seckillId, nowTime);
- if (updateCount <= 0) {
- //秒杀结束
- throw new SeckillCloseException("seckill is closed");
- } else {
- //插入购买明细
- int insertCount = successKilledDao.insertSuccessKilled(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 (SeckillCloseException e1) {
- throw e1;
- } catch (RepeatKillException e2) {
- throw e2;
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- //所有编译期异常转换为运行期异常,Spring声明式事务只支持运行期异常的回滚
- //转换的目的是为了出现编译期异常时,rollback回滚
- throw new SeckillException("seckill inner error" + e.getMessage());
- }
- }
- /**
- * 生成MD5的通用方法
- *
- * @param seckillId
- * @return
- */
- private String getMD5(long seckillId) {
- String base = seckillId + slat;
- String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
- return md5;
- }
- }
- package org.azcode.enums;
- /**
- * 使用枚举表述常量数据字典
- * Created by azcod on 2017/4/15.
- */
- public enum SeckillStateEnum {
- SUCCESS(1, "秒杀成功"),
- END(0, "秒杀结束"),
- REPEAT_KILL(-1, "重复秒杀"),
- INNER_ERROR(-2, "系统异常"),
- DATA_REWRITE(-3, "数据篡改");
- private int state;
- private String stateInfo;
- SeckillStateEnum(int state, String stateInfo) {
- this.state = state;
- this.stateInfo = stateInfo;
- }
- public int getState() {
- return state;
- }
- public String getStateInfo() {
- return stateInfo;
- }
- public static SeckillStateEnum stateOf(int index) {
- for (SeckillStateEnum stateEnum : values()) {
- if (stateEnum.getState() == index) {
- return stateEnum;
- }
- }
- return null;
- }
- }
高并发秒杀系统--Service接口设计与实现的更多相关文章
- 高并发秒杀系统--Service事务管理与继承测试
[Spring IoC的类型及应用场景] [Spring事务使用方式] [Spring事务的特性] [Spring事务回滚的理解] [Service声明式事务的配置] 1.配置事务管理器 2.配置基 ...
- 【高并发】Redis如何助力高并发秒杀系统,看完这篇我彻底懂了!!
写在前面 之前,我们在<[高并发]高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!>一文中,详细讲解了高并发秒杀系统的架构设计,其中,我们介绍了可以使用Redis存储秒杀商品的库存数量.很 ...
- Java高并发秒杀系统API之SSM框架集成swagger与AdminLTE
初衷与整理描述 Java高并发秒杀系统API是来源于网上教程的一个Java项目,也是我接触Java的第一个项目.本来是一枚c#码农,公司计划部分业务转java,于是我利用业务时间自学Java才有了本文 ...
- Java高并发秒杀系统【观后总结】
项目简介 在慕课网上发现了一个JavaWeb项目,内容讲的是高并发秒杀,觉得挺有意思的,就进去学习了一番. 记录在该项目中学到了什么玩意.. 该项目源码对应的gitHub地址(由观看其视频的人编写,并 ...
- 高并发秒杀系统--mybatis整合技巧
mybatis实现DAO接口编码技巧 1.XML文件通过namespace命名空间关联接口类 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD ...
- 高并发秒杀系统--junit测试类与SpringIoc容器的整合
1.原理是在Junit启动时加载SpringIoC容器 2.SpringIoC容器要根据Spring的配置文件加载 [示例代码] package org.azcode.dao; import org. ...
- 高并发秒杀系统方案(分布式session)
编程要有一个习惯:做参数校验 所谓的分布式session:就是用redis统一管理session. 我们这里的思路是:把token写入cookie中,客户端在随后的访问中携带cookie,服务端就能根 ...
- 高并发秒杀系统--SpringMVC整合
[SpringMVC运行流程] [Handler注解映射技巧] [请求方法的细节处理] 1.如何处理请求参数和方法参数的绑定? 2.如何限制方法接收的请求方式? 3.如何进行请求转发和重定向? 4.如 ...
- 高并发秒杀系统方案(JSR303参数校验)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring- ...
随机推荐
- Arduino内部网页代理,网页穿透,公网访问Arduino内部网页
#include <ESP8266WiFi.h> const char* id = "id"; //http://www.mcunode.com/proxy/ ...
- winserver的consul部署实践与.net core客户端使用(附demo源码)
winserver的consul部署实践与.net core客户端使用(附demo源码) 前言 随着微服务兴起,服务的管理显得极其重要.都知道微服务就是”拆“,把臃肿的单块应用,拆分成多个轻量级的 ...
- (十一)Updating Documents
In addition to being able to index and replace documents, we can also update documents. Note though ...
- 数据类型:list列表[]、元祖tuple()、dict字典{}
List 列表[] 可变的 lst = [1,2,3,4] #改 lst[(元素下标)] = '需要修改的' #通过下表修改 lst[下标:下标] = '需要修改的' #通过范围修改 #加 lst.a ...
- Swagger 配置
放行 , 不拦截. @Configuration open class MyWebMvcConfig : WebMvcConfigurationSupport() { override fun add ...
- Openstack基础环境交换机常用配置(CISCO 3750G为例)
NOTE: 用户模式提示符为:cisco> 特权模式提示符为:cisco# 全局配置模式提示符为:cisco(config)# 端口模式提示符为:cisco(config-if)# 基础操作 ...
- VS2010创建MVC4项目提示错误: 此模板尝试加载组件程序集 “NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral,
在安装VS2010时没有安装MVC4,于是后面自己下载安装了(居然还要安装VS2010 SP1补丁包).装完后新建MVC项目时却提示: 错误: 此模板尝试加载组件程序集 “NuGet.VisualSt ...
- [转帖]Ansible批量远程管理Windows主机(部署与配置)
2018-09-12 12:04:42 https://blog.51cto.com/7424593/2174156 一.测试环境介绍 Ansible管理主机: 系统: CentOS6.8 IP ...
- Win10 登陆密码不正确(安全模式仍然启动不了)
今天朋友重启Win10后,登陆密码显示不正确,是用了很多方法都不行 然后就瞎捣鼓就进去 进入BIOS将启动模式调为USB模式 重启启动不了后 再改回系统启动 就进去了(好神奇)
- vue-cli的跨域配置(自己总结)