防止 Oracle 上事务的并发错误
Prevent concurrency bugs on transactions on Oracle
我有一个为客户创建贷款的程序。客户最多只能获得 10000。
我首先读取客户要求的旧贷款金额,如果客户要求超过 10000,我会报错,否则我会插入新贷款。
create or replace NONEDITIONABLE PROCEDURE CREATE_LOAN
(
p_client_id INT,
p_requested_loan_amount DECIMAL
)
IS
v_available_amount DECIMAL DEFAULT 0;
BEGIN
--Get available amount for the client( Clients cant require more thant 10000)
SELECT 10000 - COALESCE(SUM(l.amount), 0) INTO v_available_amount
FROM loans l
WHERE l.client_id = p_client_id
AND (l.state_id = 1 OR l.state_id = 2);
--If the cliente requested more than 10000 in older loans raise error
IF p_requested_loan_amount > v_available_amount
THEN
raise_application_error( -20001, 'Not enough available amount.' );
END IF;
--Else insert new loan
INSERT INTO loans (amount, state_id, client_id)
VALUES(p_requested_loan_amount, 1, p_client_id);
END;
如何防止两个并发事务同时读取旧贷款,并且都认为它们在插入之前有可用金额。如果我使用的是 Sql 服务器,我可以提高隔离级别,这样可以防止出现问题,但它在 Oracle 上的工作方式不同。
在您的 SELECT 语句中,使用 FOR UPDATE 子句。这将获得一个行锁并阻止另一个事务也锁定该行。
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4530093713805
我有一个为客户创建贷款的程序。客户最多只能获得 10000。 我首先读取客户要求的旧贷款金额,如果客户要求超过 10000,我会报错,否则我会插入新贷款。
create or replace NONEDITIONABLE PROCEDURE CREATE_LOAN
(
p_client_id INT,
p_requested_loan_amount DECIMAL
)
IS
v_available_amount DECIMAL DEFAULT 0;
BEGIN
--Get available amount for the client( Clients cant require more thant 10000)
SELECT 10000 - COALESCE(SUM(l.amount), 0) INTO v_available_amount
FROM loans l
WHERE l.client_id = p_client_id
AND (l.state_id = 1 OR l.state_id = 2);
--If the cliente requested more than 10000 in older loans raise error
IF p_requested_loan_amount > v_available_amount
THEN
raise_application_error( -20001, 'Not enough available amount.' );
END IF;
--Else insert new loan
INSERT INTO loans (amount, state_id, client_id)
VALUES(p_requested_loan_amount, 1, p_client_id);
END;
如何防止两个并发事务同时读取旧贷款,并且都认为它们在插入之前有可用金额。如果我使用的是 Sql 服务器,我可以提高隔离级别,这样可以防止出现问题,但它在 Oracle 上的工作方式不同。
在您的 SELECT 语句中,使用 FOR UPDATE 子句。这将获得一个行锁并阻止另一个事务也锁定该行。
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4530093713805