Zuverlässigkeit von last_insert_id

24/12/2009 - 23:29 von - - | Report spam
Hi,

da ich das $dbh->last_insert_id vorher noch nicht eingesetzt habe,
wollte ich mal fragen, wie zuverlàssig das ist - bzw. wie zuverlàssig
auch wirklich eine ID zurückgegeben wird. (also unter der
Voraussetzung, daß es generell mit meiner MySQL DB funktioniert
natürlich)

Was mich an der Beschreibung dazu stört ist einmal der Satz "Returns a
value 'identifying' the row just inserted, if possible." <- "if
possible" und in "Returns undef if the driver does not support the
method or can't determine the value." <- "or can't determine the
value".

Nunja, ich möchte die ID (auto_increment) ja haben, um in weiteren
Tabellen zu der ID noch weitere Daten abzulegen. ... aber dazu muß es
auch sicher sein, daß ich auf diese Weise die ID zurück bekomme. Und
nicht, daß Perl oder MySQL auf einmal denkt "Och, heute hab ich keine
Lust ne ID zurück zu liefern, weil ich so schon ne Menge schuften
muß" ... weil wenn das passieren würde, dann wàr der kompletten
Datensatz am Ende des Scripts ungültig und das kann ich in meinem Fall
nicht gebrauchen.


Was ich mich weiterhin frage - in der Beschreibung gibt es folgenden
Satz:

"If the underlying database offers nothing better, then some drivers
may attempt to implement this method by executing "select max($field)
from $table". Drivers using any approach like this should issue a
warning if AutoCommit is true because it is generally unsafe - another
process may have modified the table between your insert and the
select. For situations where you know it is safe, such as when you
have locked the table, you can silence the warning by passing Warn =>
0 in \%attr."

Da wird geschrieben, daß die Variante max($field) unsafe ist, weil
eben ein anderer Insert eventuell auch schon was eingefügt hat. Und
für diesen Fall lieber einen lock machen sollte.

Ist denn das last_insert_id safe ? - weil man muß das ja auch separat
von $dbh abfragen und somit könnte doch dann zwischen dem execute oder
do und dann dieser Abfrage sich auch schon was in der Tabelle getan
haben (zumindestens theoretisch) - weil es wird ja laut Beschreibung
die _letzte_ ID zurück gegeben. Also müßte ich doch auch vor dem
Insert ein lock machen ?


Daher die Frage - wie zuverlàssig etc. funktioniert das
last_insert_id ?



MFG
Christoph
 

Lesen sie die antworten

#1 Ralf Döblitz
25/12/2009 - 12:55 | Warnen spam
Hi,

da ich das $dbh->last_insert_id vorher noch nicht eingesetzt habe,
wollte ich mal fragen, wie zuverlàssig das ist - bzw. wie zuverlàssig
auch wirklich eine ID zurückgegeben wird.



Das hàngt von der benutzten Datenbank und evtl. auch ihrer Konfiguration
ab.

(also unter der
Voraussetzung, daß es generell mit meiner MySQL DB funktioniert
natürlich)



MySQL oder eine Datenbank? SCNR. Warum nimmst du nicht etwas richtiges
wie z.B. PostgreSQL?

Was mich an der Beschreibung dazu stört ist einmal der Satz "Returns a
value 'identifying' the row just inserted, if possible." <- "if
possible" und in "Returns undef if the driver does not support the
method or can't determine the value." <- "or can't determine the
value".



Nicht alle RDBMS unterstützen das. Nicht alle bekommen es zuverlàssig
hin (MySQL wàre da für Fehler ein Kandidat) - man muß ja die letzte ID
aus der eigenen Transaktion bekommen, nicht die aus parallel laufenden
Inserts. Da kann man sich bei ungünstig gewàhltem Isolation-Level schon
hypsch in den Fuß schießen (geht IIRC auch mit Oracle).

Nunja, ich möchte die ID (auto_increment) ja haben, um in weiteren
Tabellen zu der ID noch weitere Daten abzulegen. ... aber dazu muß es
auch sicher sein, daß ich auf diese Weise die ID zurück bekomme. Und
nicht, daß Perl oder MySQL auf einmal denkt "Och, heute hab ich keine
Lust ne ID zurück zu liefern, weil ich so schon ne Menge schuften
muß" ... weil wenn das passieren würde, dann wàr der kompletten
Datensatz am Ende des Scripts ungültig und das kann ich in meinem Fall
nicht gebrauchen.



Wo ist das Problem? Alles in einer Transaktion fahren, Foreign-Key-
Contraint auf die entsprechenden Felder und im Zweifelsfall fliegt die
das dann halt beim Commit um die Ohren. Dafür ist SQL doch da.

Ansonsten mußt du eben dafür sorgen, daß du ein RDBMS nimmst, daß so
etwas zuverlàssig unterstützt. Bei MySQL bedeutet das, daß du die Kiste
durch Wahl geeigneter Tabellentypen auf die übliche SQL-Semantik trimmst
(voller ACID-Support) - womit das Ding dann aber auch keine Vorteile
gegenüber z.B. PostgreSQL mehr bietet. Für PostgreSQL muß man ein paar
Einschrànkungen beachten, aber wenn man das macht, dann funktioniert das
zuverlàssig.

[...]
Da wird geschrieben, daß die Variante max($field) unsafe ist, weil
eben ein anderer Insert eventuell auch schon was eingefügt hat. Und
für diesen Fall lieber einen lock machen sollte.



Klar - unzureichende Isolation. Oder eben kein AutoCommit nehmen, son-
dern die ID in der eigenen Transaktion vor dem Commit abfragen. Das
solltest bei deinem Szenario ja sowieso machen, wenn mehrere INSERT/
UPDATE-Statements logisch voneinander abhàngig sind.

Ist denn das last_insert_id safe ? - weil man muß das ja auch separat
von $dbh abfragen und somit könnte doch dann zwischen dem execute oder
do und dann dieser Abfrage sich auch schon was in der Tabelle getan
haben (zumindestens theoretisch) - weil es wird ja laut Beschreibung
die _letzte_ ID zurück gegeben. Also müßte ich doch auch vor dem
Insert ein lock machen ?



man Transaktion

Daher die Frage - wie zuverlàssig etc. funktioniert das
last_insert_id ?



MySQL unterstützt das über eine spezielle Funktion im DBD-Treiber,
sollte also ziemlich gut funktionieren und nicht den zusàtzlichen
Einschrànkungen des "select max(X)" unterworfen sein. PostgreSQL bekommt
es auch sauber hin, wenn man die Einschrànkungen in der DBD-Doku
beachtet.

Alternativ könnte man natürlich auch ganz einfach eine Sequence benutzen
und den benötigten Wert in seinem Script selbst abfragen und dann an den
entsprechenden Stellen einsetzen.

Ralf
Ralf Döblitz * Schapenstraße 6 * 38104 Braunschweig * Germany
Phone: +49-531-2361223 Fax: +49-531-2361224 mailto:
Homepage: http://www.escape.de/users/selene/
Mit UTF-8 kann man gleichzeitig àöüßÄÖÜæœłø‱¼½¾¤¹²³¢€£¥¶§¬÷×±©®™¡¿ verwenden…

Ähnliche fragen