Java高并发秒时啊API之Service层
16lz
2021-01-22
Java高并发秒时啊API之Service层1
第一章 秒杀业务接口设计与实现
---1-1----------------------------------
1.DAO层:接口设计+SQL编写(不需要其他杂七杂八的功能)
2.代码和SQL的分离,方便Review(浏览)
3.DAO拼接等逻辑在Service完成(DAO只需负责SQL语句,其他都由Service层完成)
---1-2 秒杀Service接口设计----------------------------------
DTO设计:
Exposer.java 暴露秒杀地址DTO
package org.seckill.dto;
/*
* 暴露秒杀地址DTO
*
*
* */
public class Exposer {
//是否开启秒杀
private boolean exposed;
//一种加密措施
private String md5;
private long seckillId;
//系统当前时间(毫秒)
private long now;
private long start;
private long end;
public Exposer(boolean exposed,String md5,long seckillId){
this.exposed = exposed;
this.md5 = md5;
this.seckillId = seckillId;
}
public Exposer(boolean exposed, long seckillId) {
this.exposed = exposed;
this.seckillId = seckillId;
}
public Exposer(boolean exposed, long seckillId, long now, long start, long end) {
super();
this.exposed = exposed;
this.md5 = md5;
this.seckillId = seckillId;
this.now = now;
this.start = start;
this.end = end;
}
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封装秒杀执行结果
package org.seckill.dto;
import org.seckill.entity.SuccessKilled;
/*
* 封装秒杀执行结果*/
public class SeckillExecution {
private long seckillId;
//秒杀结果状态
private int state;
//状态表示
private String stateInfo;
//秒杀成功对象
private SuccessKilled successKilled;
public SeckillExecution(long seckillId, int state, String stateInfo, SuccessKilled successKilled) {
this.seckillId = seckillId;
this.state = state;
this.stateInfo = stateInfo;
this.successKilled = successKilled;
}
public SeckillExecution(long seckillId, int state, String stateInfo) {
super();
this.seckillId = seckillId;
this.state = state;
this.stateInfo = stateInfo;
}
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 SuccessKilled getSuccessKilled() {
return successKilled;
}
public void setSuccessKilled(SuccessKilled successKilled) {
this.successKilled = successKilled;
}
public String getStateInfo() {
return stateInfo;
}
public void setStateInfo(String stateInfo) {
this.stateInfo = stateInfo;
}
}
Service层:
业务接口:站在"使用者角"度设计接口
三个方面:方法定义粒度,参数,返回类型(return 类型/exception )友好
SeckillServic.java
package org.seckill.service;
import java.util.List;
import javax.swing.text.html.parser.Entity;
import org.seckill.dto.Exposer;
import org.seckill.dto.SeckillExection;
import org.seckill.entity.Seckill;
import org.seckill.exception.RepeatKillExeception;
import org.seckill.exception.SeckillCloseException;
import org.seckill.exception.SeckillException;
/*
* 业务接口:站在"使用者角"度设计接口
* 三个方面:方法定义粒度,参数,返回类型(return 类型/exception )友好
* */
public interface SeckillService {
/*
* 查询所有秒杀记录
* @return
* */
List<Seckill> getSeckillList();
/*查询单个秒杀记录
* @param seckillId
* @retrun
*/
Seckill getById(long seckillId);
/*
* 秒杀开启时输出秒杀接口地址,
* 否则输出系统时间和秒杀 时间
* @param seckillId
* @retrun
* */
Exposer exportSeckillUrl(long seckillId);
/*
* 执行秒杀操作
* @param seckillId
* @param userPhone
* @param md5
* */
SeckillExecution executeSeckill(long seckillId,long userPhone,String md5)
throws SeckillException,RepeatKillExeception,SeckillCloseException;
}
Exception:
package org.seckill.exception;
/*
* 秒杀相关业务异常
* */
public class SeckillException extends RuntimeException{
public SeckillException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public SeckillException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
}
package org.seckill.exception;
/*
* 重复秒杀异常(运行期异常,spring的声明式事务处理的是runtime异常,如果不是这类异常,那么他是不会回滚的)
* */
public class RepeatKillExeception extends SeckillException{
public RepeatKillExeception(String message){
super(message);
}
public RepeatKillExeception(String message,Throwable cause){
super(message,cause);
}
}
package org.seckill.exception;
/*
*秒杀关闭异常
* */
public class SeckillCloseException extends SeckillException{
public SeckillCloseException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public SeckillCloseException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
}
---1-3 1-4秒杀Service接口实现1----------------------------------
SeckillServiceImpl.java
package org.seckill.service.impl;
import java.util.Date;
import java.util.List;
import org.seckill.dao.SeckillDao;
import org.seckill.dao.SuccessKilledDao;
import org.seckill.dto.Exposer;
import org.seckill.dto.SeckillExecution;
import org.seckill.entity.Seckill;
import org.seckill.entity.SuccessKilled;
import org.seckill.enums.SeckillStatEnum;
import org.seckill.exception.RepeatKillExeception;
import org.seckill.exception.SeckillCloseException;
import org.seckill.exception.SeckillException;
import org.seckill.service.SeckillService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;
public class SeckillServiceImpl implements SeckillService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private SeckillDao seckillDao;
private SuccessKilledDao successKilledDao;
//md5盐值字符串,用于混淆MD5
private final String slat = "sldijfldkjfpaojj@#(#$sldfj`123";
@Override
public List<Seckill> getSeckillList() {
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) {
Seckill seckill = seckillDao.queryById(seckillId);
if(seckill == null){
return new Exposer(false,seckillId);
}
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);//TODO
return new Exposer(true,md5,seckillId);
}
private String getMD5(long seckillId){
String base = seckillId+"/"+slat;
String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
return md5;
}
@Override
public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
throws SeckillException, RepeatKillExeception, SeckillCloseException {
if(md5==null|| !md5.equals(getMD5(seckillId))){
throw new SeckillException("seckill data rewrite");
}
//执行秒杀逻辑:减库存 + 记录购买行为
Date nowTime = new Date();
try{
int updateCount = seckillDao.reduceNumber(seckillId, nowTime);
if(updateCount <=0){
//没有更新记录
throw new SeckillCloseException("seckill is closed");
} else {
//记录购买行为
int insertCount= successKilledDao.insertSuccessKilled(seckillId, userPhone);
//唯一:insert ignore
if(insertCount <=0){
//重复秒杀
throw new RepeatKillExeception("seckill repeated");
}else {
//秒杀成功
SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
//return new SeckillExecution(seckillId,1,"秒杀成功",successKilled);
return new SeckillExecution(seckillId,SeckillStatEnum.SUCCESS);
}
}
} catch (SeckillCloseException e1) {
throw e1;
} catch (RepeatKillExeception e2) {
throw e2;
}catch (Exception e){
logger.error(e.getMessage(),e);
//所有编译期异常 转化为运行期异常
//spring事务会做roll back
throw new SeckillException("seckill inner error : "+e.getMessage());
}
return null;
}
}
SeckillExecution.java
package org.seckill.dto;
import org.seckill.entity.SuccessKilled;
import org.seckill.enums.SeckillStatEnum;
/*
* 封装秒杀执行结果*/
public class SeckillExecution {
private long seckillId;
/*此处不做枚举类型的原因:会把这个对象转换为json,通过ajax返回给前端浏览器。
* 默认的json的类库在转换枚举时有问题。
* (可以做一个把枚举类型转换为json的transfer,不过比较复杂,此处不使用此方法。
*/
//秒杀结果状态
private int state;
//状态表示
private String stateInfo;
//秒杀成功对象
private SuccessKilled successKilled;
public SeckillExecution(long seckillId, SeckillStatEnum statEnum) {
super();
this.seckillId = seckillId;
this.state = statEnum.getState();
this.stateInfo = statEnum.getStateInfo();
}
//public SeckillExecution(long seckillId, int state, String stateInfo, SuccessKilled successKilled) {
public SeckillExecution(long seckillId, SeckillStatEnum statEnum, SuccessKilled successKilled) {
super();
this.seckillId = seckillId;
this.state = statEnum.getState();
this.stateInfo = statEnum.getStateInfo();
this.successKilled = successKilled;
}
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 SuccessKilled getSuccessKilled() {
return successKilled;
}
public void setSuccessKilled(SuccessKilled successKilled) {
this.successKilled = successKilled;
}
public String getStateInfo() {
return stateInfo;
}
public void setStateInfo(String stateInfo) {
this.stateInfo = stateInfo;
}
}
SeckillStatEnum.enum
数据字典放入枚举中。
package org.seckill.enums;
//使用枚举表示常量数据
public enum SeckillStatEnum {
SUCCESS(1,"秒杀成功"),
END(1,"秒杀结束"),
REPEAT_KILL(-1,"重复"),
INNER_ERROR(-2,"系统异常"),
DATA_REWRITE(-3,"数据篡改");
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;
}
}
---1-1----------------------------------
---1-1----------------------------------
更多相关文章
- java返回值是list的时候获取list的参数类型
- 如何知道Object是否为String类型对象?
- 如何让BlockingQueue接受多种类型?
- 当只使用get()和set()方法时,用原始类型替换AtomicBoolean?
- Java中的数据类型
- Java反射---getGenericSuperclass和ParameterizedType参数化类型
- 怎么用java 实现两个web service之间调用各自的接口 实现数据的
- 黑马程序员——Java学习笔记 String类和基本数据类型对象包装类
- 接口之命令模式