2016-01-17 3 views
1

Я пишу приложение в Node.js, используя PostgreSQL в качестве базы данных. Но у меня есть некоторые проблемы. У меня есть таблица с информацией о ресурсах в регионе:Оптимистическая очередь блокировки

CREATE TABLE regions_indexes 
(
    id integer NOT NULL, 
    resource_type integer NOT NULL, 
    current_resource integer, 
    maximum_resource integer, 
    CONSTRAINT regions_indexes_pkey PRIMARY KEY (id, resource_type) 
) 

Пользователи нажимает на кнопку, приложение вычисляет различные параметры на основе current_resource, а затем сделать current_resource - $ calc_value. Потому что, возможно, я очень уверенно использую транзакции. Но при вычислении процесса возможны некоторые ошибки, и нам нужно повторять вычисления. Теперь я использую SELECT ... FOR UPDATE для блокировки строки с использованием current_resource. Как я могу сделать это без блокировки с использованием оптимистической блокировки, если текущее значение current_resource очень важно, а пользователь, который сначала нажимает, должен использовать max. avalaible current_resource. Другими словами, я должен реализовать очередь acess для current_resource.

ответ

1

Для оптимистичной блокировки вам необходимо определить некоторые средства, чтобы проверить, изменилась ли строка с тех пор, как вы видели ее в последний раз. Например, позволяет просто добавить еще один идентификатор:

alter table regions_indexes add version_id integer default 1 not null; 

Теперь приложение читает некоторые строки, показывает данные пользователю и ждет, пока кнопка не будет нажата. Мы должны помнить стоимость version_id, которую мы получили.

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

Это может выглядеть следующим образом (в псевдокод):

-- remember version_id 
select * 
from regions_indexes 
where id = ... and resource_type = ...; 

-- wait for user click 
-- you can wait for a long time, because no lock is yet acquired 
... 

update regions_indexes 
set current_resource = current_resource - ..., version_id = version_id + 1 
where id = ... and resource_type = ... 
returning version_id; 

if new_version_id = old_version_id + 1 then 
    -- success, commit 
else 
    -- fail, rollback 
end if; 

Но оптимистичным замок не работает в условиях высокой параллельности. Когда конфликты не редки, вам придется часто перезапускать транзакции.

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