秒杀系统-service
在Dao层我们只完成了针对表的相关操作,包括写了接口方法和映射文件中的sql语句,并没有编写逻辑的代码,例如对多个Dao层方法的拼接,当我们用户成功秒杀商品时我们需要进行商品的减库存操作(调用SeckillDao接口)和增加用户明细(调用SuccessKilledDao接口),这些逻辑我们都需要在Service层完成。Dao层只进行数据的访问操作,接下来我们便进行Service层代码的编写。秒杀Service接口设计如下:
()创建service包用于存放我们的Service接口和其实现类。
()创建exception包用于存放service层出现的异常,例如重复秒杀商品异常、秒杀已关闭等异常。
()创建dto包作为传输层, 用于完成web和service层的数据传递。
()创建entity包用于业务数据的封装。
service包需要的相关类名和函数名如表6-10所示。

SeckillService.java:
public interface SeckillService {
List<Seckill> getSeckillList();
Seckill getById(long seckillId);
Exposer exportSeckillUrl(long seckillId);
SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
throws SeckillException,RepeatKillException,SeckillCloseException;
SeckillExecution executeSeckillProcedure(long seckillId, long userPhone, String md5);
} SeckillServiceImpl.java:
public class SeckillServiceImpl implements SeckillService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private SeckillDao seckillDao;
@Autowired
private SuccessKilledDao successKilledDao;
@Autowired
private RedisDao redisDao;
private final String salt = "sadkfjalsdjfalksj23423^&*^&%&!EBJKH#e™£4";
@Override
public List<Seckill> getSeckillList() {
return seckillDao.queryAll(, );
}
@Override
public Seckill getById(long seckillId) {
return seckillDao.queryById(seckillId);
}
@Override
public Exposer exportSeckillUrl(long seckillId) {
Seckill seckill = redisDao.getSeckill(seckillId);
if (seckill == null) {
seckill = seckillDao.queryById(seckillId);
if (seckill == null) {
return new Exposer(false, seckillId);
} else {
redisDao.putSeckill(seckill);
}
}
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());
}
String md5 = getMD5(seckillId);
return new Exposer(true, md5, seckillId);
}
private String getMD5(long seckillId) {
String base = seckillId + "/" + salt;
String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
return md5;
}
@Override
@Transactional
public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
throws SeckillException, RepeatKillException, SeckillCloseException {
if (md5 == null || !md5.equals(getMD5(seckillId))) {
throw new SeckillException("seckill data rewrite");
}
Date nowTime = new Date();
try {
int insertCount = successKilledDao.insertSuccessKilled(seckillId, userPhone);
if (insertCount <= ) {
throw new RepeatKillException("seckill repeated");
} else {
int updateCount = seckillDao.reduceNumber(seckillId, nowTime);
if (updateCount <= ) {
throw new SeckillCloseException("seckill is closed");
} else {
SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
return new SeckillExecution(seckillId, SeckillStatEnum.SUCCESS, successKilled);
}
}
} catch (SeckillCloseException e1) {
throw e1;
} catch (RepeatKillException e2) {
throw e2;
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new SeckillException("seckill inner error:" + e.getMessage());
}
}
@Override
public SeckillExecution executeSeckillProcedure(long seckillId, long userPhone, String md5) {
if (md5 == null || !md5.equals(getMD5(seckillId))) {
return new SeckillExecution(seckillId, SeckillStatEnum.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);
int result = MapUtils.getInteger(map, "result", -);
if (result == ) {
SuccessKilled sk = successKilledDao.
queryByIdWithSeckill(seckillId, userPhone);
return new SeckillExecution(seckillId, SeckillStatEnum.SUCCESS, sk);
} else {
return new SeckillExecution(seckillId, SeckillStatEnum.stateOf(result));
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SeckillExecution(seckillId, SeckillStatEnum.INNER_ERROR);
}
}
}
在dto包中创建Exposer.java,用于封装秒杀的地址信息。SeckillExecution.java,用于判断秒杀是否成功,成功就返回秒杀成功的所有信息(包括秒杀的商品id、秒杀成功状态、成功信息、用户明细),失败就抛出一个我们允许的异常(重复秒杀异常、秒杀结束异常)。
Exposer.java:
public class Exposer {
private boolean exposed;
private String md5;
private long seckillId;
private long now;
private long start;
private long end;
@Override
public String toString() {
return "Exposer{" +
"exposed=" + exposed +
", md5='" + md5 + '\'' +
", seckillId=" + seckillId +
", now=" + now +
", start=" + start +
", end=" + end +
'}';
}
public Exposer(boolean exposed, String md5, long seckillId) {
this.exposed = exposed;
this.md5 = md5;
this.seckillId = seckillId;
}
public Exposer(boolean exposed, long seckillId, long now, long start, long end) {
this.exposed = exposed;
this.seckillId = seckillId;
this.now = now;
this.start = start;
this.end = end;
}
public Exposer(boolean exposed, long seckillId) {
this.exposed = exposed;
this.seckillId = seckillId;
}
public boolean isExposed() {
return exposed;
}
public void setExposed(boolean exposed) {
this.exposed = exposed;
}
public String getMd5() {
return md5;
}
public void setMd5(String md5) {
this.md5 = md5;
}
public long getSeckillId() {
return seckillId;
}
public void setSeckillId(long seckillId) {
this.seckillId = seckillId;
}
public long getNow() {
return now;
}
public void setNow(long now) {
this.now = now;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
}
SeckillExecution.java:
public class SeckillExecution {
private long seckillId;
private int state;
private String stateInfo;
private SuccessKilled successKilled;
@Override
public String toString() {
return "SeckillExecution{" +
"seckillId=" + seckillId +
", state=" + state +
", stateInfo='" + stateInfo + '\'' +
", successKilled=" + successKilled +
'}';
}
public SeckillExecution(long seckillId, SeckillStatEnum statEnum, SuccessKilled successKilled) {
this.seckillId = seckillId;
this.state = statEnum.getState();
this.stateInfo = statEnum.getStateInfo();
this.successKilled = successKilled;
}
public SeckillExecution(long seckillId, SeckillStatEnum statEnum) {
this.seckillId = seckillId;
this.state = statEnum.getState();
this.stateInfo = statEnum.getStateInfo();
}
public long getSeckillId() {
return seckillId;
}
public void setSeckillId(long seckillId) {
this.seckillId = seckillId;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getStateInfo() {
return stateInfo;
}
public void setStateInfo(String stateInfo) {
this.stateInfo = stateInfo;
}
public SuccessKilled getSuccessKilled() {
return successKilled;
}
public void setSuccessKilled(SuccessKilled successKilled) {
this.successKilled = successKilled;
}
}
然后需要在exception包下创建我们在秒杀业务过程中允许的异常,RepeatKillException.java用于处理重复的秒杀异常;SeckillCloseException.java用于处理秒杀关闭异常;SeckillException.java用于处理秒杀相关业务的异常。
RepeatKillException.java:
public class RepeatKillException extends SeckillException {
public RepeatKillException(String message) {
super(message);
}
public RepeatKillException(String message, Throwable cause) {
super(message, cause);
}
}
SeckillCloseException.java:
public class SeckillCloseException extends SeckillException {
public SeckillCloseException(String message) {
super(message);
}
public SeckillCloseException(String message, Throwable cause) {
super(message, cause);
}
}
SeckillException.java:
public class SeckillException extends RuntimeException {
public SeckillException(String message) {
super(message);
}
public SeckillException(String message, Throwable cause) {
super(message, cause);
}
}
在实现类SeckillServiceImpl.java中,我们用枚举的方式将异常函数中返回的常量进行封装,在enums包下创建一个枚举类型SeckillStatEnum.java,用于返回state和stateInfo这两个参数的相关数据。
SeckillStatEnum.java:
public enum SeckillStatEnum {
SUCCESS(,"秒杀成功"),
END(,"秒杀结束"),
REPEAT_KILL(-,"重复秒杀"),
INNER_ERROR(-,"系统异常"),
DATA_REWRITE(-,"数据篡改");
private int state;
private String stateInfo;
SeckillStatEnum(int state, String stateInfo) {
this.state = state;
this.stateInfo = stateInfo;
}
public int getState() {
return state;
}
public String getStateInfo() {
return stateInfo;
}
public static SeckillStatEnum stateOf(int index) {
for (SeckillStatEnum state : values()) {
if (state.getState() == index) {
return state;
}
}
return null;
}
}
使用Spring托管Service依赖配置:
在spring包下创建一个spring-service.xml文件,然后采用注解的方式将Service的实现类加入到Spring IOC容器中,然后在Service实现类的方法中,在需要进行事务声明的方法上加上事务的注解,配置如下。
spring-service.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="org.seckill.service"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
秒杀系统-service的更多相关文章
- 高并发秒杀系统--Service接口设计与实现
[DAO编写之后的总结] DAO层 --> 接口设计 + SQL编写 DAO拼接等逻辑 --> 统一在Service层完成 [Service层的接口设计] 1.接口 ...
- 高并发秒杀系统--Service事务管理与继承测试
[Spring IoC的类型及应用场景] [Spring事务使用方式] [Spring事务的特性] [Spring事务回滚的理解] [Service声明式事务的配置] 1.配置事务管理器 2.配置基 ...
- Java高并发秒杀系统API之SSM框架集成swagger与AdminLTE
初衷与整理描述 Java高并发秒杀系统API是来源于网上教程的一个Java项目,也是我接触Java的第一个项目.本来是一枚c#码农,公司计划部分业务转java,于是我利用业务时间自学Java才有了本文 ...
- Java高并发秒杀系统【观后总结】
项目简介 在慕课网上发现了一个JavaWeb项目,内容讲的是高并发秒杀,觉得挺有意思的,就进去学习了一番. 记录在该项目中学到了什么玩意.. 该项目源码对应的gitHub地址(由观看其视频的人编写,并 ...
- SSM实现秒杀系统案例
---------------------------------------------------------------------------------------------[版权申明:本 ...
- SpringBoot开发案例从0到1构建分布式秒杀系统
前言 最近,被推送了不少秒杀架构的文章,忙里偷闲自己也总结了一下互联网平台秒杀架构设计,当然也借鉴了不少同学的思路.俗话说,脱离案例讲架构都是耍流氓,最终使用SpringBoot模拟实现了部分秒杀场 ...
- 从构建分布式秒杀系统聊聊Lock锁使用中的坑
前言 在单体架构的秒杀活动中,为了减轻DB层的压力,这里我们采用了Lock锁来实现秒杀用户排队抢购.然而很不幸的是尽管使用了锁,但是测试过程中仍然会超卖,执行了N多次发现依然有问题.输出一下代码吧,可 ...
- 基于SpringMVC+Spring+MyBatis实现秒杀系统【概况】
前言 本教程使用SpringMVC+Spring+MyBatis+MySQL实现一个秒杀系统.教程素材来自慕课网视频教程[https://www.imooc.com/learn/631].有感兴趣的可 ...
- springboot项目:Redis分布式锁的使用(模拟秒杀系统)
模拟秒杀系统: 第一步:编写Service package com.payease.service; /** * liuxiaoming * 2017-12-14 */ public interfac ...
随机推荐
- Python · 进度条
(这里是本章会用到的 GitHub 地址) 我实现的这个进度条可能是可以当做一个第三方库来使用的(这个人好自大,啧),它支持记录并发程序的进度且损耗基本只来源于 Python 本身 先来看看我们的进度 ...
- python3:实现字符串的全排列(无重复字符)
最近在学一些基础的算法,发现我的数学功底太差劲了,特别是大学的这一部分,概率论.线性代数.高数等等,这些大学学的我是忘得一干二净(我当时学的时候也不见得真的懂),导致现在学习算法,非常的吃力.唉!不说 ...
- Struts vs spring mvc
1. 机制.spring mvc 的入口是servlet, 而struts是filter(这里要指出,filter和servlet是不同的.以前认为filter是servlet的一种特殊),这样就导致 ...
- 给tableView设置背景图片
经常遇到要给tableView设置背景图片的问题,但如果直接设置背景 backgroundView的话,背景图不会显示,原因是 tableView上的cell默认是不透明的颜色,所以解决方法是 让 ...
- 学习笔记:jqueryui
Jquery UI cdn.bootcss.com <!-- jquery --> <script src="http://cdn.bootcss.com/jquery/1 ...
- WEB请求过程(http解析,浏览器缓存机制,域名解析,cdn分发)
概述 发起一个http请求的过程就是建立一个socket通信的过程. 我们可以模仿浏览器发起http请求,譬如用httpclient工具包,curl命令等方式. curl "http://w ...
- ElasicSearch(4) 与jest结合
https://spring.io/projects/spring-data-elasticsearch https://docs.spring.io/spring-data/elasticsearc ...
- 数据预处理:独热编码(One-Hot Encoding)和 LabelEncoder标签编码
一.问题由来 在很多机器学习任务中,特征并不总是连续值,而有可能是分类值. 离散特征的编码分为两种情况: 1.离散特征的取值之间没有大小的意义,比如color:[red,blue],那么就使用one- ...
- TCP与UDP,可靠UDP如何实现
两种协议都是传输层协议,为应用层提供信息载体. TCP协议是基于连接的字节流的可靠协议,有三次握手,四次挥手,超时重传,流量控制(滑动窗口),拥塞控制和差错控制,也正因为有可靠性的保证和控制手段,所以 ...
- ArcGIS自定义工具箱-列举损坏的数据源
ArcGIS自定义工具箱-列举损坏的数据源 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 目的:查找地图文档中损坏的数据源链接 使用方法:参数可选,默认为当前(ar ...