• 库存扣减和锁


    常见的实现方案:

    1. 代码同步, 例如使用 synchronized ,lock 等同步方法
    2. 不查询,直接更新  update table set surplus = (surplus - buyQuantity) where id = xx and (surplus - buyQuantity) > 0
    3. 使用CAS, update table set surplus = aa where id = xx and version = y
    4. 使用数据库锁, select xx for update
    5. 使用分布式锁(zookeeper,redis等)

    1.代码同步, 使用 synchronized ,lock 等同步方法

    public synchronized void buy(String productName, Integer buyQuantity) {
     // 其他校验...
     // 校验剩余数量
     Product product  = 从数据库查询出记录;
     if (product.getSurplus < buyQuantity) {
      return "库存不足";
     }
     
     // set新的剩余数量
     product.setSurplus(product.getSurplus() - quantity);
     // 更新数据库
     update(product);
     // 记录日志...
     // 其他业务...
    }

    先说下这个方案的前提配置:

    • 使用spring 声明式事务管理
    • 事务传播机制使用默认的(PROPAGATION_REQUIRED)
    • 项目分层为controller-service-dao 3层, 事务管理在service层

    这个方案不可行,主要是因为以下几点:

    1).synchronized 作用范围是单个jvm实例, 如果做了集群,分布式等,就没用了

    2).synchronized是作用在对象实例上的,如果不是单例,则多个实例间不会同步(这个一般用spring管理bean,默认就是单例)

    3).单个jvm时,synchronized也不能保证多个数据库事务的隔离性. 这与代码中的事务传播级别,数据库的事务隔离级别,加锁时机等相关.

     

    2.不查询,直接更新

    public synchronized void buy(String productName, Integer buyQuantity) {
     // 其他校验...
     int 影响行数 = update table set surplus = (surplus - buyQuantity) where id = 1 and (surplus - buyQuantity) > 0 ;
     if (result < 0) {
      return "库存不足";
     }
     // 记录日志...
     // 其他业务...
    }

    这样确实可以实现,不过有一些其他问题:

    • 不具备通用性,例如add操作
    • 库存操作一般要记录操作前后的数量等,这样没法记录
    • 其他...

    3.使用CAS, update table set surplus = aa where id = xx and yy = y

    public void buy(String productName, Integer buyQuantity) {
     // 其他校验...
     Product product = getByDB(productName);
     int 影响行数 = update table set surplus = (surplus - buyQuantity) where id = 1 and surplus = 查询的剩余数量 ;
     while (result == 0) {
      product = getByDB(productName);
      if (查询的剩余数量 > buyQuantity) {
       影响行数 = update table set surplus = (surplus - buyQuantity) where id = 1 and surplus = 查询的剩余数量 ;
      } else {
       return "库存不足";
      }
     }
     
     // 记录日志...
     // 其他业务...
    }

    4.使用数据库锁, select xx for update

    public void buy(String productName, Integer buyQuantity) {
     // 其他校验...
     Product product = select * from table where name = productName for update;
     if (查询的剩余数量 > buyQuantity) {
      影响行数 = update table set surplus = (surplus - buyQuantity) where name = productName ;
     } else {
      return "库存不足";
     }
     
     // 记录日志...
     // 其他业务...
    }

    5.使用分布式锁(zookeeper,redis等)

    分布式锁的实现方案有很多:基于redis,基于zookeeper,基于数据库等等

  • 相关阅读:
    禁止360开机自动启动
    Google Code注册方法详解 Google Code网盘申请方法
    做程序开发工作,编程思想很重要
    EPP(Eclipse PHP)语法高亮仿EditPlus配置
    2HC32F460(华大)+BC260Y(NBIOT)基本控制篇(自建物联网平台)整体运行测试微信小程序扫码绑定BC260Y(NBIOT),并通过MQTT和单片机实现远程通信控制
    2HC32F460(华大)+BC260Y(NBIOT)基本控制篇(自建物联网平台)整体运行测试Android扫码绑定BC260Y(NBIOT),并通过MQTT和单片机实现远程通信控制
    【面向对象】宽接口、窄接口和访问方法(上)
    重构,小步进行曲
    Java中有些好的特性(一):静态导入
    【读书笔记】设计模式沉思录
  • 原文地址:https://www.cnblogs.com/KL2016/p/15494979.html
Copyright © 2020-2023  润新知