Вашите опции са:
-
Изпълнение в
SERIALIZABLE
изолация. Взаимозависимите транзакции ще бъдат прекъснати при извършване на предаване, тъй като имат неуспешна сериализация. Ще получите много нежелана поща в регистъра на грешките и ще правите много повторения, но ще работи надеждно. -
Дефинирайте
UNIQUE
ограничение и опитайте отново при неуспех, както отбелязахте. Същите проблеми като по-горе. -
Ако има родителски обект, можете да
SELECT ... FOR UPDATE
родителския обект, преди да направите свояmax
заявка. В този случай трябва даSELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE
. Вие използватеbar
като заключване за всичкиfoo
s с тозиbar_id
. След това можете да знаете, че е безопасно да продължите, стига всяка заявка, която извършва увеличаването на вашия брояч, прави това надеждно. Това може да работи доста добре.Това все още прави обобщена заявка за всяко повикване, което (за следваща опция) е ненужно, но поне не изпраща нежелана поща в регистрационния файл за грешки като горните опции.
-
Използвайте маса за брояч. Това бих направил. Или в
bar
, или в странична таблица катоbar_foo_counter
, придобийте идентификатор на ред с помощта наUPDATE bar_foo_counter SET counter = counter + 1 WHERE bar_id = $1 RETURNING counter
или по-малко ефективната опция, ако вашата рамка не може да се справи с
RETURNING
:SELECT counter FROM bar_foo_counter WHERE bar_id = $1 FOR UPDATE; UPDATE bar_foo_counter SET counter = $1;
След това в същата транзакция , използвайте генерирания брояч за
number
. Когато се ангажирате, редът на таблицата с брояч за тозиbar_id
се отключва за следваща заявка за използване. Ако се върнете назад, промяната се отхвърля.
Препоръчвам подхода на брояча, използвайки специална странична таблица за брояча, вместо добавяне на колона към bar
. Това е по-чисто за моделиране и означава, че създавате по-малко раздуване на актуализацията в bar
, което може да забави заявките към bar
.