• 使用锁解决电商中的超卖


    一、如何使用锁解决电商中的超卖的问题?

    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();
        }
    
    }
    View Code
     
  • 相关阅读:
    i3wm菜单
    开始写博客拉
    xterm配置
    Linux Tips
    docker下运行labview2010
    oracle连接字符串解析
    C# 域登录实现
    解决Winform程序在不同分辨率系统下界面混乱
    FTP设置:FTP隔离用户
    sqlserver 启动不了sqlserver服务,提示特定服务错误代码10048
  • 原文地址:https://www.cnblogs.com/callbin/p/14580186.html
Copyright © 2020-2023  润新知