欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-01-13 20:05:28
...

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();
    }
}

上一篇: SQL学习笔记08-- 事务

下一篇: