Предотвращение ошибок параллелизма в транзакциях Oracle

#oracle #transactions #isolation-level

#Oracle #транзакции #уровень изоляции

Вопрос:

У меня есть процедура, в которой a создает кредиты для клиентов. Клиенты могут получить только 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 Server, я мог бы повысить уровень изоляции, и это предотвратило бы проблему, но в Oracle это работает по-другому.

Ответ №1:

В инструкции SELECT используйте предложение FOR UPDATE . Это приведет к блокировке строки и остановит блокировку этой строки другой транзакцией.

https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4530093713805

Комментарии:

1. Почему сериализуемый уровень изоляции не предотвращает это в oracle?

2. Кажется, что в oracle вы не «видите» регистры чтения phatom.