目录
秒杀按钮
需求:点击抢购的按钮,在未规定的时间段内不可点击
代码实现:
vue的JS实现:
在vue的js中 , prop 是父组件用来传递数据的一个自定义属性
秒杀请求
需求:
点击立即秒杀后,从前端发送请求到后端接受的一系列判断
代码
前端
携带数据发送到后端
后端
Seckill-api
domain
添加两个实体类,秒杀订单信息类和订单详情信息类
Seckill-server
WebConfig
把自定义参数解析器的配置类拷贝一份到秒杀服务里面。
1、秒杀请求判断
controller
开始对秒杀的操作进行一系列的判断:是否登录、数据库是否有该商品id、后端再次判断秒杀时间是否已经开始
2、重复下单判断
判断用户是否重复下单,如果重复下单,提醒不要重复下单
Mapper
先写个Mapper,写数据库查询是否重复下单的语句
Service 接口
Impl 实现类
controller
3、库存判断
判断是否有库存,如果没有提醒库存不足
4、秒杀涉及到的操作
_01、减库存
重新建一个秒杀用的service业务层来做秒杀的业务逻辑判断,秒杀的数据会放在t_order_info 订单信息表里面
创建一个service接口,专门用来处理秒杀订单信息的业务逻辑
SeckillOrderInfoServiceImpl
在实现里面,因为减库存是减 t_seckill-goods 表的数据,所以得把减库存的实际业务逻辑写在ISeckillGoodService接口那边
ISeckillGoodService接口,写减库存的实际业务逻辑方法的接口
impl
mapper
_02、创建订单对象并保存
创建出来订单信息保存到数据库中
impl
orderNo订单编号生成使用雪花算法,需要引入一个工具类类
mapper
写sql把订单信息对象存到数据库表 t_order_info 里面
_03、用户下单次数数据存储
往 t_seckill_order 表插入一条数据作为这个用户已经下单的依据
因为t_seckill_order 只存用户的id和秒杀的id和订单编号,是用来看用户是否存在重复下单的现象,所以业务逻辑要单独写在ISeckillOrderService接口里面
mapper
写sql
出现的问题:
1、sql的update和insert的 括号要写好,具体看sql语句拼接的时候是否正常,会不会关键字和字段拼接在一起
2、秒杀的方法记得加事务注解
3、seckill-server 服务因为有用到redis,所以需要在yml配置把redis-server的配置加上,这样在项目启动的时候去gitee上面拉数据的话,就不会报错了
4、远程调用出现繁忙
出现原因:点击立即秒杀多次后,出现了这个【远程调用商品服务繁忙】的问题。
解决:后面重启,然后gitee密码修改了一下,因为显示在湛江被登录了,但是应该不是解决方法,只是记录一下
5、前端用ajax调用方法,但是后台返回数据的时候,没有走这个seccess的判断,成功和失败都没有弹窗和提示
解决:这里的success 我写成 seccess,写错了,u写成e,然后就不走那里function函数。
现在就会提示了
失败也会提示了
成功也能正常跳转页面
订单编号生成使用雪花算法的代码
package cn.ljh.shop.cloud.util;
/**
* twitter 的分布式环境全局唯一id算法 雪花算法
*/
public class IdGenerateUtil {
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long twepoch = 1288834974657L;
private long workerIdBits = 5L;
private long datacenterIdBits = 5L;
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private long sequenceBits = 12L;
private long workerIdShift = sequenceBits;
private long datacenterIdShift = sequenceBits + workerIdBits;
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private long sequenceMask = -1L ^ (-1L << sequenceBits); //4095
private long lastTimestamp = -1L;
private static class IdGenHolder {
private static final IdGenerateUtil instance = new IdGenerateUtil();
}
public static IdGenerateUtil get() {
return IdGenHolder.instance;
}
public IdGenerateUtil() {
this(0L, 0L);
}
public IdGenerateUtil(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果上次生成时间和当前时间相同,在同一毫秒内
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
}
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
protected long timeGen() {
return System.currentTimeMillis();
}
}