oracle - Oracle 包中的 SELECT ... FOR UPDATE
问题描述
我为更新语句创建了 PACKAGE 和 PACKAGE BODY,
我在 StackOverFlow 中没有找到任何关于此的内容,我想知道我这样做的方式是否好,以及您是否会更改任何内容。
如果我调用程序
begin
account_api.upd_account(1, 'user', 1000)
end;
这些过程应该被锁定,直到我用 commit 语句完成事务
CREATE OR REPLACE PACKAGE account_api AS
PROCEDURE upd_account
(
p_acc_id accounts.acc_id%type
, p_acc_name accounts.acc_name%type
, p_acc_amount accounts.acc_amount%type
);
end account_api;
/
CREATE OR REPLACE PACKAGE BODY account_api AS
PROCEDURE upd_account (
p_acc_id accounts.acc_id%type
, p_acc_name accounts.acc_name%type
, p_acc_amount accounts.acc_amount%type
)
is
l_current_balance NUMBER;
l_new_balance NUMBER;
BEGIN
SELECT acc_amount INTO l_current_balance
FROM accounts
WHERE acc_id = p_acc_id
FOR UPDATE;
l_new_balance := l_current_balance + p_acc_amount;
IF l_new_balance < 0 THEN
raise_application_error(-20001, 'Sorry you re overdrawn');
END IF;
UPDATE accounts
SET acc_amount = l_new_balance,
acc_name = p_acc_name
WHERE acc_id = p_acc_id;
COMMIT;
end;
end account_api;
/
解决方案
该过程对我来说似乎没问题,但我会将其简化为只有一个语句,并且我会添加一个显式的 ROLLBACK 语句,如下所示:
UPDATE accounts
SET acc_amount = acc_amount + p_acc_amount,
acc_name = p_acc_name
WHERE acc_id = p_acc_id
RETURNING acc_amount INTO l_new_balance;
IF l_new_balance < 0 THEN
rollback;
raise_application_error(-20001, 'Sorry you re overdrawn');
ELSE
commit;
END IF;
无需使用附加SELECT ... FOR UPDATE
来锁定行,因为 UPDATE 语句也锁定了行。感谢RETURNING INTO
条款,您可以检索新余额,然后在更新后检查它,如果新余额太低,则回滚更改,否则提交。