@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注解,注入PlatformTransactionManager和TransactionDefinition来手动提交事务
代码如下:
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-- 事务