当前位置:   article > 正文

数据库事务使用

数据库事务使用

1.启用事务

批量写入场景里要不要启用事物,其实很多人都有自己的看法,这里我给出启用于不启用的利弊,

  • 启用事务:好处在于如批量插入过程中,异常情况可以保证原子性,但是性能比不开事务低,在特大数据量下会明显低一个档次
  • 不启用事务:好处就是写入性能高,特大数据量写入性能提升明显,但是无法保证原子性

假如在批量写入过程中发生网络波动或者数据库宕机,我们其实只需要重新新建一条通知消息,然后重新操作即可。

因为上一条通知消息因为批量插入步骤没有全部完成,所以推送状态是失败。后续等开发人员处理一下脏数据即可。

2.大事务

@TransactionalSpring 框架提供得事务注解,相信这是许多人都知道的,但是在一些高性能场景下,是不建议使用的,推荐通过编程式事务来手动控制事务提交或者回滚,减少事务影响范围,因而提升性能。

2.1使用事务注解

采用 @Transactional 事务注解

  1. @Transactional(rollbackFor = Exception.class)
  2. public void doUnPaidTask(Long orderId) {
  3. // 1. 查询订单是否存在
  4. Order order = orderService.getById(orderId);
  5. ,,,
  6. // 2. 更新订单为已取消状态
  7. order.setOrderStatus((byte) OrderStatusEnum.ORDER_CLOSED_BY_EXPIRED.getOrderStatus());
  8. orderService.updateById(order);
  9. ...
  10. // 3. 订单商品数量增加
  11. LambdaQueryWrapper<OrderItem> queryWrapper = Wrappers.lambdaQuery();
  12. queryWrapper.eq(OrderItem::getOrderId, orderId);
  13. List<OrderItem> orderItems = orderItemService.list(queryWrapper);
  14. for (OrderItem orderItem : orderItems) {
  15. Long goodsId = orderItem.getGoodsId();
  16. Integer goodsCount = orderItem.getGoodsCount();
  17. if (!goodsDao.addStock(goodsId, goodsCount)) {
  18. throw new BusinessException("秒杀商品货品库存增加失败");
  19. }
  20. }
  21. // 4. 返还用户优惠券
  22. couponService.releaseCoupon(orderId);
  23. log.info("---------------订单orderId:{},未支付超时取消成功", orderId);
  24. }

可以看到上面订单回滚的代码逻辑有四个步骤,如下,

  1. 查询订单是否存在
  2. 更新订单为已取消状态
  3. 订单商品数量增加
  4. 返还用户优惠券

这里面有个问题,订单回滚方法里面其实只有 2、3、4 步骤是需要在一个事物里执行的,第 1 步其实可以放在事物外面来执行,以此缩小事物范围。

2.2使用编程式事务

使用编程式事务对其优化后,代码如下

  1. @Resource
  2. private PlatformTransactionManager platformTransactionManager;
  3. @Resource
  4. private TransactionDefinition transactionDefinition;
  5. public void doUnPaidTask(Long orderId) {
  6. // 启用编程式事务
  7. // 1. 在开启事务钱查询订单是否存在
  8. Order order = orderService.getById(orderId);
  9. ...
  10. // 2. 开启事务
  11. TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
  12. try {
  13. // 3. 设置订单为已取消状态
  14. order.setOrderStatus((byte) OrderStatusEnum.ORDER_CLOSED_BY_EXPIRED.getOrderStatus());
  15. orderService.updateById(order);
  16. ...
  17. // 4. 商品货品数量增加
  18. LambdaQueryWrapper<OrderItem> queryWrapper = Wrappers.lambdaQuery();
  19. queryWrapper.eq(OrderItem::getOrderId, orderId);
  20. List<OrderItem> orderItems = orderItemService.list(queryWrapper);
  21. for (OrderItem orderItem : orderItems) {
  22. Long goodsId = orderItem.getGoodsId();
  23. Integer goodsCount = orderItem.getGoodsCount();
  24. if (!goodsDao.addStock(goodsId, goodsCount)) {
  25. throw new BusinessException("秒杀商品货品库存增加失败");
  26. }
  27. }
  28. // 5. 返还优惠券
  29. couponService.releaseCoupon(orderId);
  30. // 6. 所有更新操作完成后,提交事务
  31. platformTransactionManager.commit(transaction);
  32. log.info("---------------订单orderId:{},未支付超时取消成功", orderId);
  33. } catch (Exception e) {
  34. log.info("---------------订单orderId:{},未支付超时取消失败", orderId, e);
  35. // 7. 发生异常,回滚事务
  36. platformTransactionManager.rollback(transaction);
  37. }
  38. }

可以看到采用编程式事务后,我们将查询逻辑排除在事务之外,这样也就减小了事物影响范围。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/412432
推荐阅读
相关标签
  

闽ICP备14008679号