2016-12-06 3 views
1

Я смущен о предмете блокировки в Oracle. Что касается моих исследований, я могу использовать FOR UPDATE NOWAIT/WAIT для блокировки строк.Реализация оптимистического блокирования в Oracle

Я хочу реализовать свой замок таким образом. Как только я выдаю FOR UPDATE, строка будет заблокирована, и я могу проверить наличие мутаций. У меня есть столбец versionNumber, который увеличивается на 1 каждый раз, когда таблица обновляется. Могу ли я использовать этот номер версии, чтобы проверить, что строка имеет или не имеет мутации? что-то вроде

if (:new.versionNum != :old.versionNum) raise_application_error(20000, 'Mutated'); end if;

Мой вопрос, где я могу идти о фактически писать строку кода FOR UPDATE? Я сделал небольшой графический интерфейс для обработки меняющихся имен и сохранения их обратно в базу данных. Это делается триггером на оракуле на этом столе или на стороне моего клиента JDBC?

Любые уточнения были бы хороши!

Thanks

+0

ВЫБЕРИТЕ ДЛЯ ОБНОВЛЕНИЯ, но я не думаю, что это оптимистичная блокировка ... – Vadim

+0

На самом деле? не могли бы вы уточнить, что выбрать для обновления? Я думал, что это заперло ряд? – wonderBoy322

+0

@ wonderBoy322 Он блокирует строку, но я бы подумал, что это пессимистическая блокировка. Это «пессимистично», потому что вы используете это, когда вы уверены, что кто-то другой попытается изменить ту же строку. В отличие от «оптимизма» и предполагая, что никто другой не изменит одну и ту же строку, поэтому вы выполняете всю работу, а затем в самом конце проверяете какой-то флаг, чтобы убедиться, что никто другой ничего не изменил. –

ответ

1

Существует два основных подхода к блокировке.

Во-первых, у вас есть пессимистическая блокировка. При таком подходе вы блокируете строку (SELECT ... FOR UPDATE), которая запрещает кому-либо изменять строку. Затем вы делаете UPDATE. Когда вы совершаете свое изменение, блокировка освобождается. В этом случае нет необходимости иметь столбец номер версии/временной метки (по крайней мере, не поддерживать блокировку), а код относительно прост.

Недостатком пессимистической блокировки является то, что вам нужно удерживать блокировку все время, когда пользователь сидит на странице, потенциально редактируя данные. Это технически очень сложно, если вы создаете веб-приложение, поскольку HTTP - это протокол без учета состояния. Запрос, который первоначально отображает страницу, обычно получает соединение из пула соединений, делает SELECT, а затем возвращает соединение с пулом после того, как страница была сделана. Последующий запрос об обновлении данных, как правило, будет происходить в другом соединении с другим сеансом базы данных, поэтому вы не можете заблокировать строку в первом сеансе и обновить ее во второй. Если вы хотите пессимистически заблокировать строку, вам нужно будет выполнить большую работу на задней стороне, чтобы убедиться, что одно соединение с базой данных привязано к определенному сеансу среднего уровня, пока пользователь не закончил редактирование данных. Это, как правило, оказывает очень негативное влияние на масштабируемость и вводит всевозможные проблемы управления сеансом - как вы знаете, например, запросил ли я страницу, заблокировал строку и затем закрыл мой браузер, даже не выйдя из системы или не внес изменения? Как долго вы собираетесь оставить запись заблокированной в базе данных? Что произойдет, если какой-либо другой сеанс пытается заблокировать строку? Как долго вы собираетесь позволить этому блоку сеанса ждать блокировки, если первый человек выйдет на обед? Как правило, люди не реализуют пессимистическую блокировку в веб-приложениях, потому что управление сеансами и состояние сеанса просто непрактичны.

Второй вариант - оптимистичная блокировка. В этом подходе вы добавляете номер версии/временную метку в строку. Вы выбираете этот номер версии/метку времени при запросе данных. Затем вы используете это в своем предложении WHERE, когда позже выполняете обновление и проверяете, сколько строк было фактически изменено. Если вы изменяете ровно одну строку, вы знаете, что строка не изменилась с момента ее чтения. Если вы изменяете 0 строк, вы знаете, что строка изменилась, и вы можете справиться с этой ошибкой.

Так, например, вы хотите выбрать данные вместе с номером версии

SELECT address_line1, city, state, zip, version 
    FROM addressTable 
WHERE address_id = `<<some key>>` 

Когда вы были готовы сделать обновление, вы могли бы сделать что-то вроде этого, где вы используете version в вашем UPDATE и выдаст ошибку, если строка изменилась

UPDATE addressTable 
    SET address_line1 = `<<new address line 1>>`, 
     city = `<<new city>>`, 
     state = `<<new state>>`, 
     zip = `<<new zip>>`, 
     version = version + 1 
WHERE address_id = `<<some key>>` 
    AND version = `<<version you read initially>>` 

IF(SQL%ROWCOUNT = 0) 
THEN 
    -- Darn. The row must have changed since you read it. Do something to 
    -- alert the user. Most likely, the application will need to re-query the 
    -- data to see what the address has been changed to and then ask the user 
    -- whether they want to re-apply the changes. 
    RAISE_APPLICATION_ERROR(-20001, 'Oops, the row has changed since you read it.'); 
END; 

Ваше приложение будет затем сделать что-то полезное с ошибкой. Как правило, это означало бы повторение чего-то вроде запроса данных, представления изменений пользователю и выяснения того, хотели ли они применить их изменения. Если, например, я прочитал адрес и начал его редактировать, перейдите на обед, мой коллега войдет в систему, прочитает один и тот же адрес, внесет некоторые изменения и сохранит его, затем я вернусь и попытаюсь сохранить мои изменения, это, как правило, имеет смысл чтобы показать мне что-то, говорящее мне, что мой коллега уже изменил адрес на что-то новое - я хочу продолжать редактирование или я хочу отказаться от них.

+0

Второй подход - это то, что я пытаюсь реализовать, но у меня просто проблемы. В первом примере вы просто вводите это в запрос SQL. Но во втором примере. Это также делается только на консоли подсказок SQL? или это делается в триггере, написанном на 'addressTable'? – wonderBoy322

+0

@ wonderBoy322 Вы не использовали бы триггер. Код, который я опубликовал, может быть частью хранимой процедуры. Или вы можете проверить количество строк, обновленных через вызовы JDBC, и поместить оператор IF в Java. –

Смежные вопросы