一、如何使用锁解决电商中的超卖的问题?
1、模拟5个线程并发执行。使用CyclicBarrier类
package com.example.distributedemo; import com.example.distributedemo.service.OrderService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @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.await(); Integer orderId = orderService.createOrder(); System.out.println("订单id:"+orderId); } catch (Exception e) { e.printStackTrace(); }finally { cdl.countDown(); } }); } cdl.await(); es.shutdown(); } }
二、 基于ReentrantLock锁解决超卖问题(方法锁)
通过手动获取事务,commit 和 rollback 检验库存和扣减库存
package com.example.distributedemo.service; import com.example.distributedemo.dao.OrderItemMapper; import com.example.distributedemo.dao.OrderMapper; import com.example.distributedemo.dao.ProductMapper; import com.example.distributedemo.model.Order; import com.example.distributedemo.model.OrderItem; import com.example.distributedemo.model.Product; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.Date; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @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(); } }