Die select for update
ist nutzlos, wenn das nächste, was Sie sowieso die Zeile aktualisieren tun ist (dies ist für alle DBMS wahr, die select for update
unterstützt)
Für Postgres dies getan werden kann in einer einzigen Anweisung eine Datenmodifizierungs CTE Verwendung:
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;
Das Update die Zeile verriegelt, wonach jede gleichzeitige einfügen/Aktualisierungsmittel (für die gleiche identry
) muss warten, bis das obige Commit oder Rollback ist.
Wenn ich brauchte (wirklich) eine lückenlose Sequenz und ich konnte mit den Skalierbarkeitsprobleme einer solchen Lösung leben (da die Anforderung wichtiger ist dann die Leistung oder Skalierbarkeit) ich wahrscheinlich, dass in Funktion setzen würde. Etwa wie folgt:
definieren die Folge (= Zähler) Tabelle
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;
nun eine Funktion erzeugen, die einen neuen Wert
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;
Gleiche wie oben behauptet: die Transaktion, die die nächste erwirbt Sequenz für eine Entität blockiert alle nachfolgenden Aufrufe der Funktion für dieselbe Entität, bis die erste Transaktion festgeschrieben (oder rückgängig gemacht) wird.
Jetzt definieren eine Tabelle, die die lückenlose Sequenz verwendet, ist ganz einfach:
create table some_table
(
id integer primary key default next_value('some_table'),
some_column text
);
Und dann tun Sie einfach:
insert into some_table (some_column) values ('foo');
Ein gleichzeitiger Einsatz in some_table
würde warten, bis die erste Transaktion verpflichtet. Der update
wird dann den festgeschriebenen Wert anzeigen und den entsprechenden nächsten Sequenzwert zurückgeben.
dieser Kurs kann auch ohne Verwendung eine default
Klausel in der Tabellendefinition erfolgen, aber dann würden Sie brauchen, um die Funktion explizit in der Insert-Anweisung nennen:
insert into some_table
(id, some_column)
values
(next_value('some_table'), 'foo');
jedoch, dass das Potenzial pitfall hat, dass Nichts zwingt Sie dazu, beim Aufruf der Funktion den korrekten Entity-Namen zu verwenden.
Alle Beispiele oben gehen davon aus, dass Auto begehen gedreht wird off
Sie dies in einem Trigger tun würde. –
dies muss SQL db agnostic sein, also brauche ich eine SQL-Anweisung für diese – ptou
Welche DBMS verwenden Sie? Das 'select for update' ist nutzlos. Führen Sie einfach das 'update' direkt aus, wodurch auch die Zeile gesperrt wird. –