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_available,IF条件将评估为真,并且INSERT和UPDATE将被执行,使库存水平降至 -1。
我理解正确吗?这是会发生的事情吗?如何避免这种情况,即可以为库存的最后一件商品创建 2 个订单?
回答
是的,您正确理解所编写的代码具有竞争条件。
假设性能要求允许悲观锁定,最简单的解决方法是FOR UPDATE在初始SELECT语句中添加 a 。这会锁定STOCKS表中的特定行,这将导致第二个会话阻塞,直到第一个会话的事务提交或回滚。然后第二个会话将看到手头的库存已减少到 0。
THE END
二维码