Spring Boot是一个开源的Java框架,它提供了一种简单的方法来管理事务。在Spring Boot中,你可以使用@Transactional
注解来启用事务管理。这个注解可以放在类级别或方法级别上。当放在类级别上时,它表示整个类中的所有方法都会在同一个事务中执行。当放在方法级别上时,它表示该方法将在一个新的事务中执行。
使用Spring Boot进行事务管理的好处是,你不需要手动配置数据库连接和事务管理器。你只需要添加相应的依赖项,并使用@Transactional
注解即可。
但是由于这样的事务支持是基于aop切面的,也就是基于动态代理的,所以该事务会有失效的风险,以下就是一个典型的例子
- @Override
- public Result seckillVoucher(Long voucherId) {
- // 1.查询优惠券
- SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
- // 2.判断秒杀是否开始
- if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
- // 尚未开始
- return Result.fail("秒杀尚未开始!");
- }
- // 3.判断秒杀是否已经结束
- if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
- // 尚未开始
- return Result.fail("秒杀已经结束!");
- }
- // 4.判断库存是否充足
- if (voucher.getStock() < 1) {
- // 库存不足
- return Result.fail("库存不足!");
- }
-
- return this.createVoucherOrder(voucherId);
- }
-
-
-
- @Transactional
- public Result createVoucherOrder(Long voucherId) {
- // 5.一人一单
- Long userId = UserHolder.getUser().getId();
-
- // 创建锁对象
- RLock redisLock = redissonClient.getLock("lock:order:" + userId);
- // 尝试获取锁
- boolean isLock = redisLock.tryLock();
- // 判断
- if(!isLock){
- // 获取锁失败,直接返回失败或者重试
- return Result.fail("不允许重复下单!");
- }
-
- try {
- // 5.1.查询订单
- int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
- // 5.2.判断是否存在
- if (count > 0) {
- // 用户已经购买过了
- return Result.fail("用户已经购买过一次!");
- }
-
- // 6.扣减库存
- boolean success = seckillVoucherService.update()
- .setSql("stock = stock - 1") // set stock = stock - 1
- .eq("voucher_id", voucherId).gt("stock", 0) // where id = ? and stock > 0
- .update();
- if (!success) {
- // 扣减失败
- return Result.fail("库存不足!");
- }
-
- // 7.创建订单
- VoucherOrder voucherOrder = new VoucherOrder();
- // 7.1.订单id
- long orderId = redisIdWorker.nextId("order");
- voucherOrder.setId(orderId);
- // 7.2.用户id
- voucherOrder.setUserId(userId);
- // 7.3.代金券id
- voucherOrder.setVoucherId(voucherId);
- save(voucherOrder);
-
- // 7.返回订单id
- return Result.ok(orderId);
- } finally {
- // 释放锁
- redisLock.unlock();
- }
-
- }
在seckillVoucher方法的最后,我们调用了this.createVoucherOder方法,而这个原方法中是添加了@Transactional事务注解的,但是由于我们在seckillVoucher方法中是通过this关键字去调用的,实际调用的就是this.createVoucherOder方法本身,而不是spring框架帮我们创建的动态代理类(添加了事务支持)的那个createVoucherOder方法,最终导致了事务的失效。