spring @Transactional事务未提交导致的并发问题

1、以下代码存在并发问题,原因是@Transactional开启事务后,执行完createOrder()方法后已经释放锁了,但是事务还没提交,此时另外一个线程获取到锁开始执行createOrder方法导致的

public class ChaoMaiConcurrencyService {

    public static final int purchaseProductId = 1;

    public static final int purchaseProductNum =1;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Transactional(rollbackFor = Exception.class)
    public synchronized Integer createOrder() throws Exception {
        Product product = productMapper.selectByPrimaryKey(purchaseProductId);

        if (product == null) {
            throw new Exception("购买商品:"+purchaseProductId+"不存在");
        }

        Integer currentCount = product.getCount();
        //校验库存
        if (purchaseProductNum > currentCount) {
            throw new Exception("商品"+purchaseProductId+"仅剩"+currentCount+"件,无法购买");
        }
        //更新库存
        productMapper.updateProductCount(purchaseProductNum,product.getId());

        //新增订单
        Order order = new Order();
        order.setOrderAmount(product.getPrice().multiply(new BigDecimal(purchaseProductNum)));
        order.setOrderStatus(1);
        order.setReceiverName("xxx");
        orderMapper.insertSelective(order);

        //新增订单明细
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());
        orderItem.setProductId(product.getId());
        orderItem.setPurchasePrice(product.getPrice());
        orderItem.setPurchaseNum(purchaseProductNum);
        orderItemMapper.insertSelective(orderItem);

        return order.getId();
    }
}

测试类代码:
@RunWith(SpringRunner.class)
@SpringBootTest
public class ChaoMaiConcurrencyTest {

    @Autowired
    private ChaoMaiConcurrencyService chaoMaiConcurrencyService;

    @Test
    public void testChaoMai() throws InterruptedException {
        CountDownLatch cdl = new CountDownLatch(5);
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5);

        ExecutorService es = Executors.newFixedThreadPool(5);
        for (int i=0;i<5;i++) {
            es.execute(()->{
               try {
                   cyclicBarrier.await();
                   Integer orderId = chaoMaiConcurrencyService.createOrder();
                   System.out.println("订单id:"+orderId);
               } catch (Exception e) {
                   e.printStackTrace();
               } finally {
                   cdl.countDown();
               }
            });
        }
    }

}

2、解决方案:不使用@Transactional注解,注入PlatformTransactionManagerTransactionDefinition来手动提交事务
代码如下:
public class ChaoMaiConcurrencyService {

    public static final int purchaseProductId = 1;

    public static final int purchaseProductNum =1;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Autowired
    private TransactionDefinition transactionDefinition;
    
    public synchronized Integer createOrder() throws Exception {
        TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
        Product product = productMapper.selectByPrimaryKey(purchaseProductId);

        if (product == null) {
            //手动回滚
            platformTransactionManager.rollback(transaction);
            throw new Exception("购买商品:"+purchaseProductId+"不存在");
        }

        Integer currentCount = product.getCount();
        //校验库存
        if (purchaseProductNum > currentCount) {
            //手动回滚
            platformTransactionManager.rollback(transaction);
            throw new Exception("商品"+purchaseProductId+"仅剩"+currentCount+"件,无法购买");
        }
        //更新库存
        productMapper.updateProductCount(purchaseProductNum,product.getId());

        //新增订单
        Order order = new Order();
        order.setOrderAmount(product.getPrice().multiply(new BigDecimal(purchaseProductNum)));
        order.setOrderStatus(1);
        order.setReceiverName("xxx");
        orderMapper.insertSelective(order);

        //新增订单明细
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());
        orderItem.setProductId(product.getId());
        orderItem.setPurchasePrice(product.getPrice());
        orderItem.setPurchaseNum(purchaseProductNum);
        orderItemMapper.insertSelective(orderItem);

        //手动提交
        platformTransactionManager.commit(transaction);
        
        return order.getId();
    }
}
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值