7-1 介绍一下你们项目中的优惠券功能
项目中优惠券功能的实现主要包括:优惠券的发放,查询优惠券,领取优惠券,根据兑换码兑换优惠券;业务流程如下:
1.创建优惠券:创建优惠券可以设置使用范围,也可以设置优惠券类型和优惠力度,还可以设置推广方式,发放数量,每人限领等。
2.发放优惠券:发放优惠券可以设置发放方式和发放时间范围以及使用有效期。
3.领取或兑换优惠券:用户可以直接领取,或者通过兑换码领取,可以通过BitMap实现用户是否领过。
7-2 你们项目中是如何防止优惠券超领的
项目中主要面临两种超领情况:多人超领问题和单人超领问题,解决方案如下所示:
多人超领问题:在我们的项目中,采用了乐观锁的CAS思想,在更新数据前先判断数据与我之前查询到的是否一致,不一致则证明有其它线程也在更新。 为了避免出现安全问题,放弃本次更新或者重新尝试一次。这种方案性能好、安全性也好,但是并发较高时,可能出现更新成功率较低的问题。在项目中,每次提交前只需要判断发行的数量是否小于总共的数量即可。
单人超领问题:在我们的项目中,这里采用了悲观锁,同步代码块,锁住用户的id,由于我们的id为Long属性,因此需要使用userId.toString().intern()来解决这个问题,现在只要两个字符串equals的结果为true,那么intern就能保证得到的结果用 ==判断也是true。
7-3 事务失效的场景有哪些
1.事务方法非public修饰:由于Spring的事务是基于AOP的方式结合动态代理来实现的。因此事务方法一定要是public的,这样才能便于被Spring做事务的代理和增强。
2.非事务方法调用事务方法:b()是一个事务方法,会被Spring事务管理。Spring会给当前类类生成一个动态代理对象,对b()做增加,实现事务效果。但是现在a()是一个非事务方法,在其中调用了b()方法,这个调用其实隐含了一个this.
的前缀。也就是说,这里相当于是直接调用原始的类中的普通方法,而非被Spring代理对象的代理方法。那事务肯定就失效了!
3.事务方法的异常被捕获:方法内部直接捕获了Exception类型的异常,也就是说方法执行过程中即便出现了异常也不会向外抛出。而Spring的事务管理就是要感知业务方法的异常,当捕获到异常后才会回滚事务。现在事务被捕获,就会导致Spring无法感知事务异常,自然不会回滚,事务就失效了。
4. 事务异常类型不对:Spring的事务管理默认感知的异常类型是RuntimeException
,当事务方法内部抛出了一个IOException
时,不会被Spring捕获,因此就不会触发事务回滚,事务就失效了。因此,当我们的业务中会抛出RuntimeException以外的异常时,应该通过@Transactional
注解中的rollbackFor
属性来指定异常类型。
5. 事务传播行为不对:慎用传播行为,注意外部事务与内部事务之间的关系。