并发订单时如何查看库存数量?
How to check the quantity in stock when making concurrent orders?
让我们想象一个具有两个 table 的数据库:items
和 orders
。第一个 table 包含所有待售商品。第二个跟踪客户的所有订单。每件商品都有一列 'quantity',表示这些商品有多少库存。下新订单时,后端会检查订购数量是否不大于库存数量。如果是这样,则不会创建订单。否则将创建订单并更新可用商品的数量。
问题是当同时创建两个订单时,同时执行两个检查并创建两个订单(彼此不知道)。结果DB中有两个总订单量大于实际库存量的订单
我已经搜索过如何处理这个问题,遇到了事务、锁、隔离等概念。我了解了这些术语,但仍未了解需要实施的架构解决方案。
我到底需要做什么来解决这个麻烦?在创建订单之前要编写什么 SQL 查询来检查库存?我应该将它包装在事务中并对其应用一些隔离级别吗?或者也许我只需要在下订单时锁定 tables?是否可以让订单创建操作等到并发订单创建后才开始?这些问题仍然没有答案。
希望得到您的帮助。谢谢!
解决问题的方法有很多种。假设您不想在这里创建一个主要的零售站点,最简单的方法是锁定项目中的行。
最简单的方法可能是在减法完成后才进行检查。
UPDATE ITEMS set quantity_avail=quantity_avail -
where part_num=
returning (quantity_avail)
然后如果返回值小于0,则回滚交易并向用户报告现在缺货。
但是现在,如果运输部门在准备运输时将其掉落在地板上并弄坏了怎么办?
对于中低交易量,您可以实施实时处理。对于高容量,您需要接近实时。
对于实时处理,有两个选项:
乐观锁定:应用程序不锁定需要修改的记录,只读取它们。当处理完成时(理想情况下是在短时间后),应用程序会使用“并发检查”更新记录。通常情况下,记录会包含版本号、时间戳,或者在极端情况下会比较整个记录。如果更新通过并发检查,那么一切都很好,事务被提交,订单完成。如果并发检查没有通过,则需要进行补偿逻辑以重试该操作,以某种方式恢复它,或者认为它失败了。这种策略的好处是可以用同样的硬件处理更多的订单。缺点是它是一个更复杂的解决方案,因为它需要处理额外的路径,而不仅仅是快乐路径。
悲观锁定:应用程序读取并锁定所有必要的记录。所有其他竞争进程都需要以相同的顺序获取所有锁。如果所有的锁都是安全的,那么就可以安全地处理订单,而不用担心在任务结束时出现问题。这种策略的好处是易于理解和调试。这种策略的缺点是获取锁的成本很高,并且会显着影响应用程序的带宽——也就是说,它每分钟可以处理多少订单。
最后,对于大批量,您可能需要满足于近实时——也就是延迟处理。有两种策略:
如果您的应用程序可以按某些标准(地区、客户、产品类型、仓库等)对订单进行分类,您可以实施微服务或一组队列,其中 service/queue 服务于不同的客户或库存项目。在这种情况下,这可以提供相当程度的并行性。
如果不能对订单进行分流,那么一个队列就可以一个一个处理所有的订单。这对于某些应用程序来说可能很慢。
让我们想象一个具有两个 table 的数据库:items
和 orders
。第一个 table 包含所有待售商品。第二个跟踪客户的所有订单。每件商品都有一列 'quantity',表示这些商品有多少库存。下新订单时,后端会检查订购数量是否不大于库存数量。如果是这样,则不会创建订单。否则将创建订单并更新可用商品的数量。
问题是当同时创建两个订单时,同时执行两个检查并创建两个订单(彼此不知道)。结果DB中有两个总订单量大于实际库存量的订单
我已经搜索过如何处理这个问题,遇到了事务、锁、隔离等概念。我了解了这些术语,但仍未了解需要实施的架构解决方案。
我到底需要做什么来解决这个麻烦?在创建订单之前要编写什么 SQL 查询来检查库存?我应该将它包装在事务中并对其应用一些隔离级别吗?或者也许我只需要在下订单时锁定 tables?是否可以让订单创建操作等到并发订单创建后才开始?这些问题仍然没有答案。
希望得到您的帮助。谢谢!
解决问题的方法有很多种。假设您不想在这里创建一个主要的零售站点,最简单的方法是锁定项目中的行。
最简单的方法可能是在减法完成后才进行检查。
UPDATE ITEMS set quantity_avail=quantity_avail -
where part_num=
returning (quantity_avail)
然后如果返回值小于0,则回滚交易并向用户报告现在缺货。
但是现在,如果运输部门在准备运输时将其掉落在地板上并弄坏了怎么办?
对于中低交易量,您可以实施实时处理。对于高容量,您需要接近实时。
对于实时处理,有两个选项:
乐观锁定:应用程序不锁定需要修改的记录,只读取它们。当处理完成时(理想情况下是在短时间后),应用程序会使用“并发检查”更新记录。通常情况下,记录会包含版本号、时间戳,或者在极端情况下会比较整个记录。如果更新通过并发检查,那么一切都很好,事务被提交,订单完成。如果并发检查没有通过,则需要进行补偿逻辑以重试该操作,以某种方式恢复它,或者认为它失败了。这种策略的好处是可以用同样的硬件处理更多的订单。缺点是它是一个更复杂的解决方案,因为它需要处理额外的路径,而不仅仅是快乐路径。
悲观锁定:应用程序读取并锁定所有必要的记录。所有其他竞争进程都需要以相同的顺序获取所有锁。如果所有的锁都是安全的,那么就可以安全地处理订单,而不用担心在任务结束时出现问题。这种策略的好处是易于理解和调试。这种策略的缺点是获取锁的成本很高,并且会显着影响应用程序的带宽——也就是说,它每分钟可以处理多少订单。
最后,对于大批量,您可能需要满足于近实时——也就是延迟处理。有两种策略:
如果您的应用程序可以按某些标准(地区、客户、产品类型、仓库等)对订单进行分类,您可以实施微服务或一组队列,其中 service/queue 服务于不同的客户或库存项目。在这种情况下,这可以提供相当程度的并行性。
如果不能对订单进行分流,那么一个队列就可以一个一个处理所有的订单。这对于某些应用程序来说可能很慢。