18 февраля 2011 г.

oracle: SELECT FOR UPDATE

Уровни изолированности транзакций
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';

Запрос зависает в 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

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

Отправить комментарий