分布式锁1:5种方案解决商品超卖的方案的优缺点

本文聚焦分布式锁,先介绍其作用与主流实现方式,接着模拟单体应用订单超卖现象。随后详细阐述五种解决冲突的方案,包括JVM本地锁、表级锁SQL、悲观锁、乐观锁和Redis乐观锁,分析各方案原理、操作及优缺点。

一 分布式锁

1.1 分布式锁的作用

在多线程高并发场景下,为了保证资源的线程安全问题,jdk为我们提供了synchronized关键字和ReentrantLock可重入锁,但是它们只能保证一个工程内的线程安全。在分布式集群、微服务、云原生横行的当下,如何保证不同进程、不同服务、不同机器的线程安全问题。jdk并没有给我们提供既有的解决方案。需要自己通过编写方案来解决,目前主流的实现有以下方式:

  1. 基于mysql关系型实现

  2. 基于redis非关系型数据实现

  3. 基于zookeeper/etcd实现

1.2  四种方案的比较

性能:一个sql > 悲观锁 > jvm锁 > 乐观锁

如果追求极致性能、业务场景简单并且不需要记录数据前后变化的情况下。 优先选择:一个sql

如果写并发量较低(多读),争抢不是很激烈的情况下优先选择:乐观锁

如果写并发量较高,一般会经常冲突,此时选择乐观锁的话,会导致业务代码不间断的重试。​ 优先选择:mysql悲观锁

不推荐jvm本地锁。

代码地址: https://gitee.com/jurf-liu/distributed-lock.git

二  模拟单体应用订单超卖现象

2.1 工程结构

2.2 编写工程代码

1.pom文件

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <version>2.3.12.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

2.配置文件

server.port=9999
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/fenbu_lock?characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=cloudiip
redis.host=172.16.116.100

 3.controller

@RestController
public class StockController {

    @Autowired
    private StockService stockService;

    @GetMapping("stock/deduct")
    public String deduct(){
       // this.stockService.deduct();
        this.stockService.deductByMsqlDb();
        return "hello stock deduct!!";
    }

}

4.service

@Service
public class StockService {
    @Autowired
    private StockMapper stockMapper;
    private Stock stock = new Stock();

    private ReentrantLock lock = new ReentrantLock();

    public void deduct(){
//        lock.lock();
//        try {
//            stock.setStock(stock.getStock() - 1);
//            System.out.println("库存余量:" + stock.getStock());
//        } finally {
//            lock.unlock();
//        }
    }
    public v
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值