parallele INSERTS
dr.colossos
- datenbank
1 Vinzenz Mai0 dr.colossos1 Vinzenz Mai0 dedlfix
Hi,
folgendes Skript wird von mindestens zwei PHP-Prozessen (A, B) parallel ausgefuehrt.
[...]
$conn->begin_transaction();
for($i = 0; $i < 5; $i++)
{
$max_id = $conn->db_get_value('select max(primary_id) + 1 AS max_id from tabelle');
$conn->db_access('insert into tabelle (primary_id) VALUES ('.$max_id.')');
}
$conn->end_transaction();
[...]
Es startet jeweils eine Transaktion, ermittelt die aktuell hoechste ID der Tabelle und addiert 1, und schreibt einen neuen Satz mit dieser neuen hoechten ID, und wiederholt das (hier testweise insgesamt 5 mal in der for-Schleife), und beendet die Transaktion.
Dadurch, dass dieses Skript parallel von mehrerer Prozessen ausgefuehrt wird, kann es sein, dass Prozess A beim 1. Durchlauf der Schleife einen neuen Datensatz mit ID Y anlegen will, und dadurch, das Prozess B parallel laeuft, auch dieser einen Datensatz mit ID Y anlegen will, da er die max-id ermittelt hat, bevor (!) Prozess A das INSERT ausgefuehrt hat.
Ich habe das einige Male getestet, in der Regel funktioniert es, da, sobald ein INSERT begonnen wurde, der andere Prozess, der ja auch in einer Transaktion liegt wartet, bis die andere INSERT-Batch-Transaktion fertig ist.
Allerdings hat es auch ein paar mal aus oben genannten Grund gekracht, da die SELECTS (fast) gleichzeitig fertig waren und vorallem BEVOR einer der INSERTS abgesetzt wurde.
Wie kann man das 100% umgehen?
Trigger, Auto-ID, Locks?
Danke & Servus
Hallo
for($i = 0; $i < 5; $i++)
{
$max_id = $conn->db_get_value('select max(primary_id) + 1 AS max_id from tabelle');
$conn->db_access('insert into tabelle (primary_id) VALUES ('.$max_id.')');
}
Aua! Das macht man nicht. Verwende den Mechanismus, den Dir Dein DBMS oder
Dein DB-Abstraktionslayer bietet.
Auto-ID
Sequenzen, Identity-Werte, ... wie auch immer. Ich weiß ja nicht, was Deine
Zielplattform unterstützt.
Freundliche Grüße
Vinzenz
Hi,
und danke fuer deine Antwort.
"Ich weiß ja nicht, was Deine Zielplattform unterstützt."
Ja, ich will's halt auf "allen" laufen lassen koennen. Dass das keine gute Loesung ist weiss ich, ich habe nur auf was allgemeines gehofft, das ueberall funktioniert, ohne abstahieren zu muessen.
Auto-ID ist inzwischen verbreitet (MSSQL, PGSQL koennen das, glaub ich), aber ORACLE macht das glaub ich nur via Trigger ...
Hat noch jemand eine Idee?
Danke
Hallo
"Ich weiß ja nicht, was Deine Zielplattform unterstützt."
Ja, ich will's halt auf "allen" laufen lassen koennen. Dass das keine gute Loesung ist weiss ich, ich habe nur auf was allgemeines gehofft, das ueberall funktioniert, ohne abstahieren zu muessen.
"alle" gibt es nicht, das weißt Du doch sicher auch. Ich kann mir nicht vorstellen, dass Du etwa noch dBase unterstützen willst.
Welche Zielplattformen kommen für Dich denn in Frage?
Auto-ID ist inzwischen verbreitet (MSSQL, PGSQL koennen das, glaub ich), aber ORACLE macht das glaub ich nur via Trigger ...
ORACLE stellt meines Wissens Sequenzen zur Verfügung, vergleichbar zu SERIAL/BIGSERIAL von PostgreSQL.
Was machen übrigens Deine netten beginTransaction()-, endTransaction()-Aufrufe,
wenn das DBMS Transaktionen gar nicht unterstützt?
Freundliche Grüße
Vinzenz
Hehe,
jaja, das "alles" war natuerlich Schrott, schon klar .. waer mir am liebsten, aber das ist eine Illusion.
Was auch noch eine Moeglichkeit waere ist GUIDs/UUIDs als IDs zu verwenden.
Ja, ich denke man kann da auch einige Besucher hier entweder weiss oder rot im Gesicht anlaufen sehen, aber ich stell das trotzdem mal zur Diskussion.
Das ist dann je nach "Sicherheit" des Zufallsgenerators was zwischen microtime, PHPs uniqid() und dessen Abwandlungen, bis hin zur Simulations von GUIDs [2c6973e6-828d-4ddf-afc9-2eb2d308de8d].
Vorteile:
Nachteil:
Meinungen, Wutausbrueche oder Schreikraempfe die jemand loswerden will?
Danke
echo $begrüßung;
Ja, ich will's halt auf "allen" laufen lassen koennen. Dass das keine gute Loesung ist weiss ich, ich habe nur auf was allgemeines gehofft, das ueberall funktioniert, ohne abstahieren zu muessen.
Es gibt genügend Datenbankabstraktionen unter PHP.
Sequenzen kann man simulieren, man braucht dazu aber etwas Locking und eine extra Tabelle. Jede Sequenz bekommt darin ihren eigenen Datensatz. Sperren, Wert auslesen, Wert erhöhen, Freigeben.
echo "$verabschiedung $name";