I have a procedure where a create loans for clients. Clients can get only 10000 max. I first read the amount requested by the client on old loans, if the client has requested more than 10000 I raise an error else I insert a new loan.
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;
How can I prevent two concurrent transaction from reading the old loans at the same time and both beliving that they have available amount before they insert. If I were using Sql Server I could increase the isolation level and that would prevent the problem, but it does not work the same way on Oracle.
In your SELECT statement, use the FOR UPDATE clause. This will get a row lock and stop another transaction from locking that row too.
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4530093713805