Уровни изолированности транзакций
oracle: transaction level SERIALIZABLE
Для обеспечения повторяемости при чтении в Oracle не нужно использовать SELECT FOR UPDATE — это делается только для обеспечения последовательного доступа к данным.
Результат SELECT FOR UPDATE имеет несколько сторон
1. Никакая другая транзакция не изменяет те же данные
Запрос зависает в ses2 до тех пор пока в ses1 не сделают commit, сразу после этого запрос в ses2 выполняется.
2. 1-я сессия делает запрос в момент, когда 2-я сессия изменила данные
ses2> commit;
ses1> выполнился зависший запрос
Чтобы не было зависания нужно делать SELECT FOR UPDATE NOWAIT
Если не указывать SELECT FOR UPDATE, то каждая сессия будет работать согласовано по чтению и никаких блокировок не будет.
ORACLE всегда обеспечивает согласованность по чтению на уровне запроса и при этом данные НИКОГДА не блокируются для чтения другими процессами (это фундаментальное отличие oracle от других баз данных).
Если нужно чтобы в транзакции повторный запрос дал те же результаты, т.е. чтобы его не изменила другая сессия, то нужно использовать SELECT FOR UPDATE или установить уровень изолированности транзакции SERIALIZABLE (что дает не только повторяемость при чтении строки, но и повторяемость при выполнении любого запроса — если два раза выполнить один и тот же запрос в пределах транзакции с таким уровнем изолированности, будут получены одинаковые результаты)
oracle: transaction level SERIALIZABLE
Для обеспечения повторяемости при чтении в Oracle не нужно использовать SELECT FOR UPDATE — это делается только для обеспечения последовательного доступа к данным.
Результат SELECT FOR UPDATE имеет несколько сторон
1. Никакая другая транзакция не изменяет те же данные
ses1>select * from t;
USERNAME USER_ID
------------------------------ ----------
SYS 1
ses1>select * from t for update;
USERNAME USER_ID
------------------------------ ----------
SYS 1
ses2> update t set user_id='2' where username='SYS';
USERNAME USER_ID
------------------------------ ----------
SYS 1
ses1>select * from t for update;
USERNAME USER_ID
------------------------------ ----------
SYS 1
ses2> update t set user_id='2' where username='SYS';
Запрос зависает в ses2 до тех пор пока в ses1 не сделают commit, сразу после этого запрос в ses2 выполняется.
2. 1-я сессия делает запрос в момент, когда 2-я сессия изменила данные
ses2> update t set user_id='2' where username='SYS';
ses1> select * from t for update;
В результате ses1 зависает и ждёт пока ses2 не зафиксиорует изменения(сделает commit)ses2> commit;
ses1> выполнился зависший запрос
Чтобы не было зависания нужно делать SELECT FOR UPDATE NOWAIT
ses2> update t set user_id='2' where username='SYS';
ses1> select * from t for update nowait;
ORA-00054: resource busy and acquire with NOWAIT specified
Т.е. в ses1 выполнение запроса заканчивается ошибкой и сессия не ждёт фиксирования транзакции в ses1 Если не указывать SELECT FOR UPDATE, то каждая сессия будет работать согласовано по чтению и никаких блокировок не будет.
ORACLE всегда обеспечивает согласованность по чтению на уровне запроса и при этом данные НИКОГДА не блокируются для чтения другими процессами (это фундаментальное отличие oracle от других баз данных).
Если нужно чтобы в транзакции повторный запрос дал те же результаты, т.е. чтобы его не изменила другая сессия, то нужно использовать SELECT FOR UPDATE или установить уровень изолированности транзакции SERIALIZABLE (что дает не только повторяемость при чтении строки, но и повторяемость при выполнении любого запроса — если два раза выполнить один и тот же запрос в пределах транзакции с таким уровнем изолированности, будут получены одинаковые результаты)
sql> set transaction isolation level serializable;
oracle: transaction level SERIALIZABLE
Комментариев нет:
Отправить комментарий