2016-05-05 3 views
0

У меня есть две таблицы (это очень упрощенная модель моего случая использования):SQL: обновление счетчика колонки и вставить новую строку

- TableCounter with 2 columns: idEntry, counter 
- TableObject with 1 column : idEntry , seq (with the pair idEntry/seq unique) 

мне нужно, чтобы иметь возможность в 1 сделки:

- increase counter for idEntry = x 
- insert (x,new_counter_value) in the TableObject. 

зная, что я не должен терять последовательность, и это транзакция очень параллельная и называется много.

Как вы могли бы написать такую ​​транзакцию в инструкции (а не для хранимой процедуры)? Вы бы заблокировали строку TableCounter для idEntry = x?

Пока у меня это есть, но я ищу лучшее решение.

BEGIN TRANSACTION; 
SELECT counter FROM TableCounter WHERE idEntry=1 FOR UPDATE; 
UPDATE TableCounter SET counter=counter+1 WHERE idEntry=1; 
INSERT INTO TableObject(idEntry, seq) SELECT TableCounter.idEntry, TableCounter.counter FROM TableCounter WHERE TableCounter.idEntry = 1; 
COMMIT TRANSACTION 

Спасибо

+0

Вы бы сделать это в качестве триггера. –

+0

это должно быть SQL db agnostic, поэтому мне нужен оператор SQL для этого – ptou

+0

Какая СУБД вы используете? 'select for update' бесполезен. Просто запустите 'update' напрямую, что также заблокирует строку. –

ответ

1

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'); 

Однако это имеет потенциал ловушки, что ничто не заставляет вас использовать правильное имя объекта при вызове функции.


Все приведенные выше примеры предполагают, что авто фиксации повернута от

+0

, предполагая, что вы также хотите масштабируемость, что было бы поэтому оптимальным решением для создания бесщелевой последовательности, если бы вы точно знали, что dbms - postgresql и вы можете использовать любую его особенность? – ptou

+0

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

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