SpringBoot实现Java高并发秒杀系统之Service层开发

本文详细介绍了在SpringBoot中实现高并发秒杀系统Service层的开发,包括业务层接口设计、方法粒度控制、参数和返回值定义。重点讲解了`findById`、`findAll`、`exportSeckillUrl`以及`executeSeckill`方法的设计思路,特别是接口防刷和事务控制。同时,讨论了如何处理异常和保证接口公平性,以防止接口被恶意刷取。最后,探讨了Spring声明式事务管理在Service层的应用及其注意事项。
摘要由CSDN通过智能技术生成

Service接口的设计

之前我们写好了DAO层的接口,这里我们要开始着手编写业务层接口,然后编写业务层接口的实现类并编写业务层的核心逻辑。

设计业务层接口,应该站在 使用者 角度上设计,如我们应该做到:

  • 1.定义业务方法的颗粒度要细。
  • 2.方法的参数要明确简练,不建议使用类似Map这种类型,让使用者可以封装进Map中一堆参数而传递进来,尽量精确到哪些参数。
  • 3.方法的return返回值,除了应该明确返回值类型,还应该指明方法执行可能产生的异常(RuntimeException),并应该手动封装一些通用的异常处理机制。

类比DAO层接口的定义,我这里先给出完整的 SeckillService.java 的定义(注意:在DAO层(Mapper)中我们定义了两个接口 SeckillMapper 和 SeckillOrderMapper ,但是Service层接口为1个):

public interface SeckillService {
 /**
 * 获取所有的秒杀商品列表
 *
 * @return
 */
 List<Seckill> findAll();
 /**
 * 获取某一条商品秒杀信息
 *
 * @param seckillId
 * @return
 */
 Seckill findById(long seckillId);
 /**
 * 秒杀开始时输出暴露秒杀的地址
 * 否者输出系统时间和秒杀时间
 *
 * @param seckillId
 */
 Exposer exportSeckillUrl(long seckillId);
 /**
 * 执行秒杀的操作
 *
 * @param seckillId
 * @param userPhone
 * @param money
 * @param md5
 */
 SeckillExecution executeSeckill(long seckillId, BigDecimal money, long userPhone, String md5)
 throws SeckillException, RepeatKillException, SeckillCloseException;
}

这里我将依次讲解一下为什么接口会这样设计?接口方法的返回值是怎样定义的?

findById和findAll方法

这两个方法就简单很多:

  • findById(): 顾名思义根据ID主键查询。按照接口的设计我们需要指定参数是 seckillId (秒杀商品的ID值。注意:这里定义为 long 类型,不要定义为包装类类型,因为包装类类型不能直接进行大小比较,必须转换为基本类型才能进行值大小比较);返回值自然是查询到的商品表数据级 Seckill 实体类了。
  • findAll(): 顾名思义是查询数据库中所有的秒杀商品表的数据,因为记录数不止一条,所以一般就用List集合接收,并制定泛型是 List<Seckill> ,表示从数据库中查询到的列表数据都是Seckill实体类对应的数据,并以Seckill实体类的结构将列表数据封装到List集合中。

exportSeckillUrl方法

exportSeckillUrl() 方法可有的讲了,他是 暴露接口 用到的方法,目的就是 获取秒杀商品抢购的地址 。

1.为什么要单独创建一个方法来获取秒杀地址?

在之前我们做的后端项目中,跳转到某个详情页一般都是:根据ID查询该详情数据,然后将页面跳转到详情页并将数据直接渲染到页面上。但是秒杀系统不同,它也不能就这样简单的定义,要知道秒杀技术的难点就是如何应对高并发?同一件商品,比如瞬间有十万的用户访问,而还存在各种黄牛,有各种工具去抢购这个商品,那么此时肯定不止10万的访问量的,并且开发者要尽量的保证每个用户抢购的公平性,也就是不能让一个用户抢购一堆数量的此商品。

这就是我们常说的 接口防刷 问题。因此单独定义一个获取秒杀接口的方法是有必要的。

2.如何做到接口防刷?

接口方法: Exposer exportSeckillUrl(long seckillId); 从参数列表中很易明白:就是根据该商品的ID获取到这个商品的秒杀url地址;但是返回值类型 Exposer 是什么呢?

思考一下如何做到 接口防刷?

  1. 首先要保证该商品处于秒杀状态。也就是1.秒杀开始时间要<当前时间;2.秒杀截止时间要>当前时间。
  2. 要保证一个用户只能抢购到一件该商品,应做到商品秒杀接口对应同一用户只能有唯一的一个URL秒杀地址,不同用户间秒杀地址应是不同的,且配合订单表 seckill_order 中 联合主键的配置实现。

针对上面的两条分析,我们给出 Exposer 的设计(要注意此类定义在 /dto/ 路径下表明此类是我们手动封装的结果属性,它类似JavaBean但又不属于,仅用来封装秒杀状态的结果,目的是提高代码的重用率):

此例源码请看ÿ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值