14 Stimmen

Holen Sie sich alle eingefügten IDs beim Einfügen mehrerer Zeilen mit einer einzelnen Abfrage

Ich habe bereits andere Antworten angesehen und fühle immer noch, dass meine Frage relevant ist und einen separaten Eintrag verdient.

Ich habe eine Tabelle namens Einstellungen (in der Benutzereinstellungen gespeichert sind) und ich muss mehrere Einstellungen für jeden Benutzer einfügen. Zunächst hatte ich für jede Einstellung eine separate Einfügeanweisung ausgeführt, aber nachdem ich das nicht als besonders gute Methode empfunden hatte, dachte ich daran, mehrere Zeilen mit derselben Einfügeanweisung einzufügen. Mein einziges Problem ist, dass ich die auto_incremented IDs jeder der neu eingefügten Zeilen haben möchte.

Ich habe Antworten gelesen, die sagen, dass dies nicht möglich/skalierbar usw. ist, aber ich denke, dass ich die Lösung gefunden habe. Ich möchte Feedback, ob mein Weg richtig ist oder nicht, und deshalb diese Frage.

Was ich gemacht habe, ist einfach. Nach dem Einfügen der mehreren Zeilen rufe ich last_insert_id() auf, um die ID der ersten Zeile der gleichzeitig eingefügten Zeilen zu erhalten. Ich habe bereits die Anzahl der eingefügten Zeilen, also erstelle ich einfach ein neues Array und fülle es mit IDs, die bei last_insert_id() beginnen und bei last_insert_id()+n-1 enden (wobei n die Anzahl der eingefügten Zeilen ist).

Ich denke, dass dies funktionieren wird, aus folgenden Gründen:

1.) Die MYSQL-Dokumentation besagt, dass last_insert_id() von der Verbindung abhängig ist und wenn ein anderer Client/ eine andere Verbindung neue Datensätze einfügt, hat dies keinen Einfluss auf das last_insert_id() des anderen Clients.

2.) Ich denke, dass, da der Einfügevorgang durch eine einzelne SQL-Anweisung durchgeführt wird, die gesamte Einfügung als einzelne Transaktion behandelt werden sollte. Wenn das zutrifft, sollten ACID-Regeln gelten und die auto_incremented Werte sequenziell sein. Ich bin mir bei diesem Punkt nicht sicher.

Das sind meine Gründe, warum ich denke, dass die Logik funktionieren sollte. Also lautet meine Frage: Wird die obige Logik unter ALLEN Bedingungen funktionieren? Kann ich darauf vertrauen, dass sie in allen Situationen korrekt funktioniert? Ich weiß, dass es derzeit für mich funktioniert.

1voto

bato3 Punkte 2490

Wenn Sie gerne spielen, dann machen Sie das :)

Um zu 99% sicher zu sein, müssten Sie die Tabelle für das Schreiben sperren. Sie sind sich nicht sicher, dass die (in Zukunft) zwei Transaktionen nicht miteinander verflochten werden könnten.

Um zu 100% sicher zu sein, sollten Sie diese Werte lesen. (Oder analysieren Sie die Quelle MySQL) Die beste Lösung wäre, das Datum zu den Tabelleneinstellungen hinzuzufügen und die neuesten zu lesen. Wenn Sie die Struktur nicht ändern möchten, können Sie Trigger verwenden http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html.

Eine gute Lösung wäre es, alle Ihre Einstellungen zu aktualisieren oder nur Paare: Schlüssel - Einstellungsname

1voto

Ja͢ck Punkte 165747

Dieses Verhalten sollte nicht verlassen werden; abgesehen von den offensichtlichen Sperrproblemen, sagen wir, Sie möchten Master<->Master-Replikation einrichten; plötzlich inkrementieren sich die IDs jedes Mal um 2.

Abgesehen davon, anstatt tatsächlich mehrere INSERT-Anweisungen zu schreiben, könnte es sich lohnen, vorbereitete Anweisungen zu verwenden:

$db = new PDO(...);
$db->beginTransaction();
$stmt = $db->prepare('INSERT INTO `mytable` (a, b) VALUES (?, ?)');

foreach ($entries as $entry) {
    $stmt->execute(array($entry['a'], $entry['b']));
    $id = $db->lastInsertId();
}

$db->commit();

0voto

Ich stimme @anigel zu. Sie können nicht sicher sein, dass einige Transaktionen nicht durcheinander geraten. Sie können die Einfügungen in separate Abfragen aufteilen, für jede einzelne Abfrage last_insert_id() aufrufen und ein Array mit den Ergebnissen füllen.

Zugegeben, dies kann die Verarbeitungszeit erhöhen, aber zumindest können Sie Konflikte vermeiden. Außerdem ist es sehr unwahrscheinlich, dass Sie für jede Client-Anfrage eine große Anzahl von Transaktionen durchführen müssen, da es sich um eine Einstellungstabelle handelt.

0voto

txpeaceofficer09 Punkte 161

Wie wäre es mit:

$id = array();

$sql = "INSERT INTO `table` VALUES ('', 'foo', 'bar');";
$sql .= "INSERT INTO `table` VALUES ('', 'foo', 'bar');";
$sql .= "INSERT INTO `table` VALUES ('', 'foo', 'bar');";
$sql .= "INSERT INTO `table` VALUES ('', 'foo', 'bar');";
$sql .= "INSERT INTO `table` VALUES ('', 'foo', 'bar');";
$sql .= "INSERT INTO `table` VALUES ('', 'foo', 'bar');";

if ($db=new mysqli('host', 'user', 'pass', 'dbase'))
{
    $db->multi_query($sql);

    if ( isset($db->insert_id) ) $id[] = $db->insert_id;

    while ($db->more_results())
    {
        if ($db->next_result()) $id[] = $db->insert_id;
        else trigger_error($db->error);
    }

    $db->close();
}
else trigger_error($db->error);

if (count($id) == 0) trigger_error('Uh oh! No inserts succeeded!');
else print_r($id);

Vielleicht gibt das deine Einfüge-IDs zurück, wie du es möchtest. Ich habe es nicht getestet, aber vielleicht könntest du es für deinen Zweck anpassen und wer weiß, es könnte tatsächlich funktionieren.

0voto

sravis Punkte 3496

Ich mache das schon in meiner App. Ich füge Datensätze in einer Schleife ein und wenn jeder Datensatz eingefügt ist, speichere ich die Auto-Increment-Kennung im Array, indem ich last_insert_id() aufrufe. So kann ich das Array der eingefügten Kennungen überall dort verwenden, wo ich es brauche.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X