Distributed lock [Based on synchronized lock to solve oversold problem, distributed lock solution, distributed lock realized by pessimistic lock] (2) - comprehensive detailed explanation (learning summary --- from entry to deepening)

 

Table of contents

 Distributed lock problem_demo problem

 Solve the oversold problem based on synchronized lock

Distributed lock solution

 Distributed lock implementation scheme

 Distributed lock solution_distributed lock implemented by database pessimistic lock

 Use for update in the project


 

 Distributed lock problem_demo problem

 start order service 9090

 Start order service 9091

 

 Create two SpringBoot services

 Start the Nginx service

Download Nginx windows service, official website http://nginx.org/en/download.html

 

 Configure load balancing

Edit the nginx.conf file to add load balancing configuration.

upstream test{
      server localhost:9090 ;
      server localhost:9091 ;
   }
    
server {
        listen       80;
        server_name localhost;
    
        location / {
            proxy_pass http://test;
       }
}

Start the Nginx service

Under the nginx directory

 Start the JMeter pressure measurement tool

Add Thread Group -> HTTP Request -> View Result Tree -> Aggregate Report

 Set Http request parameters

 View inventory data

 view order data

 Solve the oversold problem based on synchronized lock

 Spring has carried out a unified abstraction and formed the PlatformTransactionManager transaction manager interface, and all operations such as transaction submission and rollback are entrusted to it.

The overall interface design of the transaction function 

Three interface functions In a word, the transaction manager updates the transaction status based on the basic information of the transaction when operating the transaction.

 method locking

public synchronized String createOrder(Integer produceId, Integer purchaseNum) { }

Declare the transaction manager

@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;

Manually create transactions

TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);

Commit the transaction manually

    /**
     * 创建订单
     *
     * @param produceId   商品id
     * @param purchaseNum 购买数量
     * @return
     */
    @Override
    public synchronized String createOrder(Integer produceId, Integer purchaseNum) {
        TransactionStatus transaction = platformTransactionManager.getTransaction(trans
actionDefinition);
        // 1、根据商品id获取商品信息
        Product product = productMapper.selectById(produceId);
        // 2、判断商品是否存在
        if (product == null) {
          platformTransactionManager.rollback(transaction);
            throw new RuntimeException("购买商品不存在");
       }
         log.info(Thread.currentThread().getName() + "库存数量" + product.getCount());
        // 3、校验库存
        if (purchaseNum > product.getCount()) {
           platformTransactionManager.rollback(transaction);
            throw new RuntimeException("库存不足");
       }
        // 4、更新库存操作
        int count = product.getCount() - purchaseNum;
        product.setCount(count);
        productMapper.updateById(product);
        // 5、创建订单
        TOrder order = new TOrder();
        order.setOrderStatus(1);//订单状态
        order.setReceiverName("张三");
        order.setReceiverMobile("18587781058");
      order.setOrderAmount(product.getPrice().multiply(new BigDecimal(purchaseNum)));//订单价格
        baseMapper.insert(order);
        // 6、创建订单和商品关联
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());//订单id
        orderItem.setProduceId(product.getId());// 商品id
        orderItem.setPurchasePrice(product.getPrice());// 购买价格
        orderItem.setPurchaseNum(purchaseNum);// 购买数量
        orderItemMapper.insert(orderItem);
        //提交事务
        platformTransactionManager.commit(transaction);
        return order.getId();
   }

Distributed lock solution

 The distributed CAP theory tells us that "any distributed system cannot satisfy Consistency, Availability, and Partition tolerance at the same time, and can only satisfy two at the same time." Therefore, many systems are in At the beginning of the design, it is necessary to make a trade-off between these three. In most scenarios in the Internet field, it is necessary to sacrifice strong consistency in exchange for high availability of the system. The system often only needs to ensure "final consistency", as long as the final time is within the acceptable range of users.

 Distributed lock implementation scheme

Distributed lock based on database implementation

 The distributed lock based on the database is mainly implemented by using the unique index of the database. The unique index is naturally exclusive, which just meets our requirements for locks: only one competitor is allowed to acquire the lock at the same time.

 Distributed lock based on Redis

 Using Redis to implement distributed locks has the highest efficiency and the fastest locking speed, because Redis is almost a pure memory operation, while the database-based and Zookeeper-based solutions both involve disk file IO, and the efficiency is relatively low. Generally, Redis is used to implement distributed locks by using the SETNX key value command of Redis. It will only succeed when the key does not exist. If the key already exists, the command will fail.

Distributed lock based on Zookeeper 

 Zookeeper is generally used as a configuration center. Its principle of implementing distributed locks is similar to that of Redis. We create temporary sequential nodes in Zookeeper and use the feature that nodes cannot be created repeatedly to ensure exclusivity.

 Distributed lock solution_distributed lock implemented by database pessimistic lock

 What is a pessimistic lock

As the name suggests, it is a pessimistic lock, always assuming the worst case, every time you go to get the data, you think that others will modify it, so every time you get the data, you will lock it, so that others will block if they want to get the data until it gets the lock.

Demo for update

Open 2 command line interfaces

 test for update

 Use for update in the project

configuration file add configuration

mybatis-plus:
 mapper-locations: classpath:mapper/*.xml

mapper add method

public interface ProductMapper extends BaseMapper<Product> {
    Product  findById(@Param("id")Integer id);
}

Mapper writes the statement

<select id="findById" parameterType="int" resultType="com.tong.lock.entity.Product">
       select * from product where id = #{id} for update
</select>

Modify the order interface implementation class

@Transactional(rollbackFor = Exception.class)
    @Override
    public  String createOrder(Integer productId, Integer count) {
        // 1、根据商品id查询商品信息
        Product product = productMapper.findById(productId);
        // 2、判断商品是否存在
        if (product == null) {
            throw new RuntimeException("购买商品不存在:" + productId + "不存在");
       }
        // 3、校验库存
        if (count > product.getCount()) {
            throw new RuntimeException("商品" +productId + "仅剩" + product.getCount() + "件,无法购买");
       }
        // 4、计算库存
        Integer leftCount = product.getCount() - count;
        // 5、更新库存
        product.setCount(leftCount);
        productMapper.updateById(product);
        // 6、 创建订单
        TOrder order = new TOrder();
        order.setOrderStatus(1);//待处理
        order.setReceiverName("张三");
        order.setReceiverMobile("18587781068");
        order.setOrderAmount(product.getPrice().multiply(new BigDecimal(count)));//订单价格
        baseMapper.insert(order);
        // 7、 创建订单和商品关系数据
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());
        orderItem.setProduceId(product.getId());
        orderItem.setPurchasePrice(product.getPrice());
        orderItem.setPurchaseNum(count);
        orderItemMapper.insert(orderItem);
        return order.getId();
   }

Pressure measurement throughput

Guess you like

Origin blog.csdn.net/m0_58719994/article/details/131711163