"currval" - Falsche Werte

Hallo,

Und zwar hab ich zwei komplett identische Schemas. schem_1 und schem_2.

beide haben eine Tabelle sessions mit einem Feld id, type serial. Und zwar will ich eine Neue Zeile einfügen und danach die neue Id auslesen.

Das mach ich wie folgt:

BEGIN;



INSERT INTO schem_2.sessions ...

Auslesen

SELECT currval('schem_2.sessions_id_seq');



COMMIT;

Das Problem ist, dass alles wunderbar läuft (255,256,257…), aber irgendwann einfach eine 5,6,7 (inkrementell) zurückgegeben wird (was natürlich falsch ist).

Hat jemand eine Idee warum das der Fall sein könnte?

Hab versucht ein Table Lock auf die Tabelle zu setzen, macht kein unterschied. Es werden manchmal immer diese Zahlen zurückgegeben.

Es scheint wirklich, als ob manchmal ab 6,7,8 inkrementiert und einmal ab 270,… (bei dem eigentlichen wert) nur mit dem Unterschied, dass bei der Rückgabe des kleineren Wertes kein neuer Eintrag generiert wird.

So hab mal komplett alles geleert (alle Tabellen)… er vergibt einige Werte zweimal

New Session with ID:9
New Session with ID:10
New Session with ID:11
New Session with ID:12
New Session with ID:13
New Session with ID:14
New Session with ID:9
New Session with ID:15

PS:
Bei einem zweiten Schema funktioniert alles wunderbar und ohne probleme :frowning:

Kannst du mal nacheinander alle Befehle, die du absetzt und bei den SELECTs die Ergebnisse hinschreiben?
Die ganze Vorgehensweise ist bisher ziemlich verwirrend.

  1. Verbindungsaufbau

  2. Begin Transaction

  3. Insert new session (tabelle sessions) (via preparedStatement)

  4. SELECT currval(‘schema.sessions_id_seq’) as new_sessionid;
    Hier passiert der Fehler, manchmal gibt er irgendwelche wirren Session-Id’s zurück, die teilweise nicht per Insert befehl eingefügt wurden oder die bereits in der Tabelle sind.

  5. Commit.

Das ist der gesamte Vorgang.

Also, ganz konkrete Frage: fügst du für die SERIAL Spalte auch einen Wert ein oder lässt du diese Spalte in deinem Query aussen vor?

Jep, beim Insert-Query ist definitiv der id-Wert NULL (nicht angegeben)

INSERT … (text,time) VALUES (‘mein bestimmter text’, 12321 )

Also, currval() liefert den letzten Wert zurück, der automatisch in dieser Verbindung generiert wurde. Diese Werte sind immer fortlaufend (ausser die Sequenz wurde anders definiert).


Ich weiss nicht, was genau du dort suchst, aber du hast ein komplettes Beispiel noch nicht gepostet, samt Ein- und Ausgaben.

Hm … das ist genau das was ich mache nur in Java geschrieben. Wenn das im Zyklus von 1x pro sec passiert funktioniert alles wunderbar. Wenn aber der Aufruf (in 30 Unter-Threads, die jeweils eine eig. Verbindung aufbauen) passiert, kommt genau 1-2 ein schwachsinniger Wert raus und dann funktioniert alles wieder … :confused:

Gibt es Fehlermeldungen? Werden diese abgefangen und geprüft?

Wenn jeder Thread eine eigene Verbindung aufbaut, nutzt trotzdem jeder Thread nur diesen einen Query oder gibt es da unterschiedliche?

In deinem Fall wäre es vielleicht mal praktisch, das Query Logging in der Datenbank zu aktivieren und zu schauen, was genau dort ausgeführt wird.

Alle Thread machen genau das gleiche (sind alles die gleichen Threads). Feldermeldungen werden soweit ordentlich abgefangen (daher erhalte ich auch später dann die Überschneidungen).

Ich werd mal per Query Logging mal schauen was ich finde. Soweit besten Danke für die kleine Analyse.

das was du hier beschreibst ist definitiv ein Problem deiner Applikation, nicht von Postgres.

Forsch da mal nach.

Grüße

Jochen

Also Wie ich oben beschrieben habe, hab ich zwei Schemas, welche die gleiche Struktur haben. Wenn ich entweder A oder B verwende, funktioniert alles wunderbar. Wenn jedoch bei gleichzeitig in Benutzung sind, tritt genau der Fehler auf… soweit aktuell

  • SERIAL Werte werden pro Verbindung vergeben und zwischengespeichert. Das bedeutet, das du aus einer anderen Verbindung heraus nicht auslesen kannst, welches die letzte vergebene ID ist.
  • SERIAL Werte wiederholen sich nicht (ausser nach einem Überlauf, aber der dürfte hier nicht das Problem sein).
  • Default Werte aus der Sequenz werden nur vergeben, wenn du selber keinen Wert für diese Spalte angibst. Tust du das, wird der gegebene Wert angenommen und die Sequenz nicht angefasst (also auch nicht weitergezählt).
  • Das Leeren einer Tabelle setzt nicht die Sequenz zurück, dafür musst du die Tabelle neu erstellen (oder die Sequenz gesondert zurücksetzen).


    So, wenn das alles zur Fehlersuche nicht hilft, würden wir gerne Auszüge aus dem Log sehen (log_min_duration_statement = 0 für alle Queries loggen).
  • SERIAL Werte werden pro Verbindung vergeben und zwischengespeichert. Das bedeutet, das du aus einer anderen Verbindung heraus nicht auslesen kannst, welches die letzte vergebene ID ist.

Also per Transaktion scheint wohl alles soweit super zu funktionieren (ich hab 20 Rechner die gleichzeitig laufen).

Wie würde man so etwas per postgreSQL anders Integrieren? D.h. Datensatz erstellen (+generierte ID auslesen?)

Das funktioniert doch. Du öffnest eine Session zur DB, erstellt einen Datensatz unter Verwendung einer Sequence, und liest den currval() aus. Das funktioniert bei einem oder 2000 gleichzeitigen Clients. Natürlich auch bei anderen Anzahlen von Clients.

Andreas

Wie würde man so etwas per postgreSQL anders Integrieren? D.h. Datensatz erstellen (+generierte ID auslesen?)

Auch wenn ich die Frage nicht ganz verstehe (was menst du mit integrieren?), Du hast folgende Optionen
1.) Datensatz einfügen → dann currval(seqname) auslesen
2.) nextval(seqname) ausführen (vergibt einen neuen pk) → und dann daten mit dem neuen pk(!!!) einfügen

Welche der beiden Optionen du wählst, ist dir überlassen, sie erzeugen quasi das gleiche Ergebnis.

Grüße

Jochen

Ahh, einfach aber wirklich interessant! Danke für dein Feedback. Was ich jedoch nicht verstehe ist, dass solche Probleme entstehen (wie oben geschrieben), dass manchmal Fehlerhafte Ergebnisse für currval zurückgeliefert werden.
Könnte das damit in Zusammenhang stehen, dass Beide Schemas die gleichen Sequenz-Namen haben?

Nur, wenn du die falsche Sequenz benutzt/abfragst.

Du kannst das ja mal prüfen, indem du selbst nextval() für jede der beiden Sequenzen aufrufst und schaust, was die jeweils zurückliefern und ob die Werte in das Fehlerschema passen.