2个用户同时运行一个存储过程-如果一次执行中的DML语句影响并行执行中的测试/条件,会发生什么?

假设我有一个用于创建销售订单的 PL/SQL 存储过程,如下所示:

CREATE OR REPLACE PROCEDURE save_order 
(
  o_output_status               OUT BINARY_INTEGER,
  i_customer                    IN  VARCHAR2,
  i_product_code                IN  VARCHAR2,
  i_quantity                    IN  BINARY_INTEGER
)
IS

  l_stock_available               BINARY_INTEGER;

BEGIN

  o_output_status := -1;

  SELECT available
    INTO l_stock_available
    FROM stock
   WHERE product = i_product_code
  ;

  IF l_stock_available >= i_quantity THEN

    INSERT INTO sales_orders (order_number, customer, product, quantity)
         VALUES (order_seq.nextval, i_customer, i_product_code, i_quantity)
    ;

    -- hello

    UPDATE stock
       SET available = available - i_quantity
     WHERE product = i_product_code
    ;

    o_output_status := 0;

  END IF;

END save_order;

我认为这一切都很简单。但我想知道的是当 2 个用户同时运行这个存储过程时会发生什么。假设某些产品只剩下 1 个单位。如果 user1 首先运行存储过程,尝试创建 1 个单位的订单,l_stock_available得到值 1,IF条件评估为真,INSERT然后UPDATE执行。

然后 user2 稍后运行存储过程,同时尝试为 1 个单位创建订单。比方说,SELECT INTO用户2被甲骨文在执行的瞬间是user1的执行已达成的评论hello。此时,user2 也将获得 1 的值l_stock_availableIF条件将评估为真,并且INSERTUPDATE将被执行,使库存水平降至 -1。

我理解正确吗?这是会发生的事情吗?如何避免这种情况,即可以为库存的最后一件商品创建 2 个订单?

回答

是的,您正确理解所编写的代码具有竞争条件。

假设性能要求允许悲观锁定,最简单的解决方法是FOR UPDATE在初始SELECT语句中添加 a 。这会锁定STOCKS表中的特定行,这将导致第二个会话阻塞,直到第一个会话的事务提交或回滚。然后第二个会话将看到手头的库存已减少到 0。


以上是2个用户同时运行一个存储过程-如果一次执行中的DML语句影响并行执行中的测试/条件,会发生什么?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>