Я предположил также, что компилятор не генерирует код относительно "a", поскольку на это не ссылаются, но тем не менее, это не правильное поведение, поскольку деструктор делает что-то, что должно быть выполнено.
Так, я попробовал в VS2008/vc9 (+SP1), Отладка и Выпуск, и ~A называют после того, как исключение выдается, выходя f () - который является правильным поведением, если я прав.
Теперь я просто попробовал VS2005/vc8 (+SP1), и это - то же поведение.
я использовал точки останова, чтобы быть уверенным. Я просто сверился с консолью, и у меня есть сообщение "~A" также. Возможно, Вы сделали это неправильно где-то в другом месте?
ваше решение должно работать: ваше первое обновление заблокирует всю таблицу. Если другая транзакция не будет завершена, обновление будет ждать. Ваше второе обновление гарантирует, что только одна строка будет иметь значение 1, потому что вы блокируете таблицу (однако это не препятствует операциям INSERT).
Вы также должны убедиться, что строка с RISK_MODEL_ID
существует (или у вас будет нулевая строка со значением «1» в конце транзакции).
Чтобы предотвратить одновременное выполнение инструкций INSERT, вы должны ЗАБЛОКИРОВАТЬ таблицу (в ЭКСКЛЮЗИВНОМ РЕЖИМЕ).
Вы можете рассмотреть возможность использования уникального, основанного на функциях индекса, чтобы позволить Oracle обрабатывать ограничение наличия только одной строки с активированным флагом, установленным на 1.
CREATE UNIQUE INDEX MODEL_IX ON MODEL ( DECODE(ACTIVATED, 1, 1, NULL));
Это остановило бы наличие более чем одной строки флаг установлен в 1, но не означает, что всегда есть одна строка с установленным флагом 1.
Если вы хотите убедиться, что одновременно может выполняться только одна транзакция, вы можете использовать синтаксис FOR UPDATE
. Поскольку у вас есть одна строка, которая требует блокировки, это очень эффективный подход.
declare
cursor c is
select activated
from model
where activated = 1
for update of activated;
r c%rowtype;
begin
open c;
-- this statement will fail if another transaction is running
fetch c in r;
....
update model
set activated = 0
where current of c;
update model
set activated = 1
where risk_model_id = ?;
close c;
commit;
end;
/
commit
освобождает блокировку.
По умолчанию ожидается освобождение строки. В противном случае мы можем указать NOWAIT
, и в этом случае любой другой сеанс, пытающийся обновить текущую активную строку, немедленно завершится ошибкой, или мы можем добавить параметр WAIT
с временем опроса. NOWAIT
- это вариант, который позволяет полностью избежать риска зависания, а также дает нам возможность сообщить пользователю, что кто-то другой обновляет таблицу, о чем он может захотеть узнать.
Этот подход гораздо более масштабируем, чем обновление всех строк в таблице. Используйте индекс на основе функций, как показал WW, чтобы обеспечить соблюдение правила, согласно которому только одна строка может иметь ACTIVATED = 1.