@Service
@Slf4j
public class OrderService {
@Resource
private OrderMapper orderMapper;
@Resource
private OrderItemMapper orderItemMapper;
@Resource
private ProductMapper productMapper;
//购买商品id
private int purchaseProductId = 100100;
//购买商品数量
private int purchaseProductNum = 1;
// 平台事务管理器
@Autowired
private PlatformTransactionManager platformTransactionManager;
// 事物的定义
@Autowired
private TransactionDefinition transactionDefinition;
private Lock lock = new ReentrantLock();
// @Transactional(rollbackFor = Exception.class)
public Integer createOrder() throws Exception{
Product product = null;
// 加锁了
lock.lock();
try {
// 手动设置事物
TransactionStatus transaction1 = platformTransactionManager.getTransaction(transactionDefinition);
product = productMapper.selectByPrimaryKey(purchaseProductId);
if (product==null){
platformTransactionManager.rollback(transaction1);
throw new Exception("购买商品:"+purchaseProductId+"不存在");
}
//商品当前库存
Integer currentCount = product.getCount();
System.out.println(Thread.currentThread().getName()+"库存数:"+currentCount);
//校验库存
if (purchaseProductNum > currentCount){
// 事物回滚
platformTransactionManager.rollback(transaction1);
throw
new Exception("商品"+purchaseProductId+"仅剩"+currentCount+"件,无法购买");
}
// 增量更新库存
productMapper.updateProductCount(purchaseProductNum,"xxx",new Date(),product.getId());
platformTransactionManager.commit(transaction1);
}finally {
//释放锁
lock.unlock();
}
TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
Order order = new Order();
order.setOrderAmount(product.getPrice().multiply(new BigDecimal(purchaseProductNum)));
order.setOrderStatus(1);//待处理
order.setReceiverName("xxx");
order.setReceiverMobile("13311112222");
order.setCreateTime(new Date());
order.setCreateUser("xxx");
order.setUpdateTime(new Date());
order.setUpdateUser("xxx");
orderMapper.insertSelective(order);
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(order.getId());
orderItem.setProductId(product.getId());
orderItem.setPurchasePrice(product.getPrice());
orderItem.setPurchaseNum(purchaseProductNum);
orderItem.setCreateUser("xxx");
orderItem.setCreateTime(new Date());
orderItem.setUpdateTime(new Date());
orderItem.setUpdateUser("xxx");
orderItemMapper.insertSelective(orderItem);
// 手动提交事务
platformTransactionManager.commit(transaction);
return order.getId();
}
}
主要方法是:
通过lock.lock();开启重入锁,在该锁下面开启事务,查询库存、校验库存以及增量更新库存,在库存为空或者库存不足时,需要跑出异常,使得事务可以回滚,最后提交事务。
在该锁块中需要使用try…finally…确保异常时,可以调用 lock.unlock();,使锁能够被释放。
然后再下面写订单的操作也需要开启一个新的事务。
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class DistributeDemoApplicationTests {
@Autowired
private OrderService orderService;
@Test
public void concurrentOrder() throws InterruptedException {
Thread.sleep(60000);
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:加上之后,线程会在这里等待(等5个线程),然后一起执行
cyclicBarrier.await();
Integer orderId = orderService.createOrder();
System.out.println("订单id:"+orderId);
} catch (Exception e) {
e.printStackTrace();
}finally {
cdl.countDown();
}
});
}
cdl.await();
es.shutdown();
}
}
通过cyclicBarrier.await();使得五个线程等待,然后并发执行,最后都要调用cdl.countDown();
在代码最后使用cdl.await();等待所有线程执行完毕,才将线程池关闭。