select for update
бесполезно, если следующая вещь, которую вы делаете, чтобы обновить строку в любом случае (это верно для любой СУБД, которая поддерживает select for update
)
Для Postgres это можно сделать в одном операторе, используя данные, изменяющие КТР:
with updated as (
update tablecounter
set counter = counter + 1
where identry = 1
returning identry, counter
)
insert into tableobject (identry, seq)
select identry, counter
from updated;
обновления будет блокировать строку, а это значит, что любое параллельную вставку/обновление (для того же identry
) придется подождать, пока это не будет выполнено или отменено.
Если я (на самом деле), требуется беспрерывное последовательность, и я мог бы жить с проблемами масштабируемости такого решения (поскольку требование является более важным, чем производительность или масштабируемость), я бы, вероятно, положить, что в функцию. Что-то вроде следующего:
Определение таблицы последовательности (= счетчик)
create table gapless_sequence
(
entity text not null primary key,
sequence_value integer not null default 0
);
-- "create" a new sequence
insert into gapless_sequence (entity) values ('some_table');
commit;
Теперь создадим функцию, которая утверждает новое значение
create function next_value(p_entity text)
returns integer
as
$$
update gapless_sequence
set sequence_value = sequence_value + 1
where entity = p_entity
returning sequence_value;
$$
language sql;
То же, что и выше: сделки, приобретающей следующий последовательность для объекта блокирует все последующие вызовы функции для одного и того же объекта, пока первая транзакция не будет совершена (или откат).
Теперь определение таблицы, которая использует беспрерывную последовательность довольно легко:
create table some_table
(
id integer primary key default next_value('some_table'),
some_column text
);
И тогда вы просто сделать:
insert into some_table (some_column) values ('foo');
Параллельной вставка в some_table
будет ждать, пока первая транзакция не. Затем update
увидит зафиксированное значение и вернет соответствующее следующее значение последовательности.
Конечно, это может быть сделано без использования оговорки в определении таблицы default
, но тогда вам нужно будет вызвать функцию в явном виде вставки заявления:
insert into some_table
(id, some_column)
values
(next_value('some_table'), 'foo');
Однако это имеет потенциал ловушки, что ничто не заставляет вас использовать правильное имя объекта при вызове функции.
Все приведенные выше примеры предполагают, что авто фиксации повернута от
Вы бы сделать это в качестве триггера. –
это должно быть SQL db agnostic, поэтому мне нужен оператор SQL для этого – ptou
Какая СУБД вы используете? 'select for update' бесполезен. Просто запустите 'update' напрямую, что также заблокирует строку. –