7-1 介绍一下你们项目中的优惠券功能
在项目中优惠券功能被设置为一个单独的微服务
首先, 管理员在管理端可以在优惠券管理页面可查看优惠券列表。
优惠券发放可立即发放、定时发放。
优惠券的使用期限分为固定天数与固定时间段两种
然后,学生端就可以查询到优惠券并选择领取方式
优惠券领取可手动领取和指定领取。
优惠券的领取本质上是像数据表中添加一条数据
最后,学生端就可以在领取到有效的优惠券之后在支付页面购买课程时使用优惠券
优惠券需要在下单页面去使用,并且涉及到多种规则计算
例如:
-
无门槛、满减都有,怎么取最优
-
满减、每满减冲突,如何做取舍
-
叠加使用,算法应该怎么实现
-
下单使用了优惠券,退单怎么退?优惠券此时该如何处理
因此我们汇总与优惠券有关的核心接口有5个:
-
根据订单查询可用优惠方案(是否到达满减门槛、是否适用此分类)
-
根据订单和优惠方案查询优惠明细
-
核销优惠券
-
退还优惠券
-
查询优惠规则
最后得到使用优惠券的流程
首先,先分出两种最优情况:
-
用券相同时,优惠金额最高的方案
-
优惠金额相同时,用券最少的方案
接下来我们就逐步来完成这个功能,大概步骤包括:
-
定义接口
-
查询用户的优惠券
-
初步筛选(过滤基本条件不满足的数据)
-
细筛并完成全排列
-
计算优惠明细
-
基于CompleteableFuture做并行计算(提升计算性能)
-
筛选最优解
最终完成优惠券的操作
7-2 你们项目中是如何防止优惠券超领的
在项目中,优惠券超领分为多人超领和单人超领两种情况
对于多人超领来说,导致这种现象的原因是由于多个线程同时操作一个共享的资源,导致产生了并发安全的问题,解决方式是加锁来处理,我在项目中使用的是乐观锁来解决,具体来讲就是在更新数据前先判断数据与我之前查询到的是否一致,不一致则证明有其它线程也在更新。为了避免出现安全问题,放弃本次更新或者重新尝试一次。
对于单人超领来说,导致这种现象的原因是是因为多个用户并发场景下,实时查询的判断逻辑会存在失效问题,解决方案是使用synchronized锁,锁的条件设置为用户id,从而实现一个用户只能抢到一次优惠券
7-3 事务失效的场景有哪些
常见的事务失效场景有5种:
1.事务方法非public修饰:
由于Spring的事务是基于AOP的方式结合动态代理来实现的。因此事务方法一定要是public的,这样才能便于被Spring做事务的代理和增强。
2.非事务方法调用事务方法
调用事务方法的是非事务的方法,而不是spirng代理对象的代理方法
3.事务方法的异常被捕获
由于在事务方法中的代码捕获了异常, 也就是说方法执行过程中即便出现了异常也不会向外抛出。而Spring的事务管理就是要感知业务方法的异常,当捕获到异常后才会回滚事务。现在事务被捕获,就会导致Spring无法感知事务异常,自然不会回滚,事务就失效了。
4.事务异常类型不对
Spring的事务管理默认感知的异常类型是RuntimeException,当事务方法内部抛出了类型不同的异常时,异常不会被spirng捕获,也就不会触发事务的回滚,事务也就失效了,解决方法是在方法的@Transactional注解中使用rollbackFor属性来指定异常类型
5.事务的传播行为不对
如果在方法调用中设置了错误的传播行为,可能导致事务无法正确传播和管理。例如,如果一个方法被错误地设置为 REQUIRES_NEW
,而实际上应该使用 REQUIRED
,就可能导致不必要的事务嵌套,或者事务无法正确传播。所以, 在设计和调用方法时,需要考虑事务传播的影响,确保方法之间的事务传播行为是一致且合理的。
以上是常见的事务失效场景