Laravel Eloquent ORM-Transaktionen

96

Das eloquente ORM ist ganz nett, obwohl ich mich frage, ob es eine einfache Möglichkeit gibt, MySQL-Transaktionen mit innoDB auf die gleiche Weise wie PDO einzurichten, oder ob ich das ORM erweitern müsste, um dies zu ermöglichen?

wesside
quelle

Antworten:

165

Du kannst das:

DB::transaction(function() {
      //
});

Alles innerhalb des Abschlusses wird innerhalb einer Transaktion ausgeführt. Wenn eine Ausnahme auftritt, wird automatisch ein Rollback durchgeführt.

Laurence
quelle
1
Innerhalb des Abschlusses kann ich Abfragen in einer Klasse aufrufen? Es wird funktionieren?
Rafael Soufraz
Leider funktioniert es bei mir nicht, wenn ich eine Instanz verschiedener Modelle erstelle, die Datensätze in ihren eigenen relevanten Methoden speichern.
Volatil3
Wenn ich innerhalb meiner Transaktion eine Ausnahme abfange (zum Generieren von Fehlermeldungen usw.), muss ich die Ausnahme erneut ausgeben, damit das Rollback auftritt?
Alexw
3
Gute Antwort, aber ein paar Dinge haben mich aufgefallen: 1. Sie müssen "use DB;" hinzufügen. Um dies zu tun, z. B. oben in Ihrer Modelldatei 2. Im Gegensatz zu JS erhalten Sie keinen Zugriff auf lokale Variablen im übergeordneten Bereich, es sei denn, Sie übergeben sie explizit. Sie müssen also das Konstrukt "use" hinzufügen ... DB :: transaction (function () use ($ user) {... Sachen, die auf $ user verweisen ...});
Polsonby
Discussed in more detail hereLink ist tot.
Tomloprod
100

Wenn Sie keine anonymen Funktionen mögen:

try {
    DB::connection()->pdo->beginTransaction();
    // database queries here
    DB::connection()->pdo->commit();
} catch (\PDOException $e) {
    // Woopsy
    DB::connection()->pdo->rollBack();
}

Update : Für Laravel 4 ist das pdoObjekt nicht mehr öffentlich, also:

try {
    DB::beginTransaction();
    // database queries here
    DB::commit();
} catch (\PDOException $e) {
    // Woopsy
    DB::rollBack();
}
Jürgen Paul
quelle
15
Sie können auch die Verknüpfungsmethoden DB::beginTransaction()& DB::commit()& verwenden DB::rollback(). Das wäre etwas sauberer.
Flori
2
Bitte aktualisieren Sie, um den @ Flori-Vorschlag zu verwenden. Es ist sauberer. Wenn Sie die neue Antwort nach oben verschieben, wird Ihre Antwort weniger verwirrend. Ich habe die erste Methode angewendet, bevor ich zur zweiten zurückkam.
frostymarvelous
Für ältere Version von Laravel benötigen Sie möglicherweise:DB::connection()->getPdo()->beginTransaction();
stattdessen
Ich persönlich denke, dass der DB::transactionRückruf mit noch sauberer ist, aber der Nachteil ist, dass Sie, wenn Sie verschiedene Handler für verschiedene Ausnahmen angeben müssen, zur Try / Catch-Technik zurückkehren müssen
OzzyTheGiant
33

Wenn Sie Eloquent verwenden möchten, können Sie dies auch verwenden

Dies ist nur ein Beispielcode aus meinem Projekt

        /* 
         * Saving Question
         */
        $question = new Question;
        $questionCategory = new QuestionCategory;

        /*
         * Insert new record for question
         */
        $question->title = $title;
        $question->user_id = Auth::user()->user_id;
        $question->description = $description;
        $question->time_post = date('Y-m-d H:i:s');

        if(Input::has('expiredtime'))
            $question->expired_time = Input::get('expiredtime');

        $questionCategory->category_id = $category;
        $questionCategory->time_added = date('Y-m-d H:i:s');

        DB::transaction(function() use ($question, $questionCategory) {

            $question->save();

            /*
             * insert new record for question category
             */
            $questionCategory->question_id = $question->id;
            $questionCategory->save();
        });
Aditya Kresna Permana
quelle
Der question->idAusdruck beim Transaktionsrückruf gibt Null zurück.
Christos Papoulas
@ChristosPapoulas meinten Sie, wir können die Auto-Inkrement-ID in der Transaktion nicht erhalten?
Hallojinjie
26

Wenn Sie Verschlüsse vermeiden möchten und gerne Fassaden verwenden, hält Folgendes Folgendes für schön und sauber:

try {
    \DB::beginTransaction();

    $user = \Auth::user();
    $user->fill($request->all());
    $user->push();

    \DB::commit();

} catch (Throwable $e) {
    \DB::rollback();
}

Wenn Anweisungen fehlschlagen, wird Commit niemals ausgeführt und die Transaktion wird nicht verarbeitet.

Chris
quelle
Wenn Anweisungen fehlschlagen, werden nachfolgende Anweisungen nicht ausgeführt. Sie müssen die Transaktion noch explizit zurücksetzen.
Jason
1
@ Jason Ich habe die Antwort aktualisiert. Ich hatte zwei Gedanken darüber, ob ich für die meisten (alle?) Datenbank-Engines, wenn die Verbindung beendet wird, nicht festgeschriebene Transaktionsabfragen nicht festgeschrieben werden sollte. Ich stimme jedoch dem zu, was Sie sagen, und wahrscheinlich am besten explizit
Chris
18

Ich bin sicher, Sie suchen keine Verschlusslösung. Versuchen Sie dies für eine kompaktere Lösung

 try{
    DB::beginTransaction();

    /*
     * Your DB code
     * */

    DB::commit();
}catch(\Exception $e){
    DB::rollback();
}
imal hasaranga perera
quelle
9

Aus irgendeinem Grund ist es ziemlich schwierig, diese Informationen irgendwo zu finden, deshalb habe ich beschlossen, sie hier zu veröffentlichen, da mein Problem, obwohl es sich auf eloquente Transaktionen bezog, dies genau änderte.

Nach der Lektüre THIS Stackoverflow Antwort, erkannte ich meine Datenbank - Tabellen MyISAM statt InnoDB verwendet wurden.

Damit Transaktionen auf Laravel (oder an einem anderen Ort, wie es scheint) funktionieren, müssen Ihre Tabellen InnoDB verwenden

Warum?

Zitieren von MySQL- Transaktionen und Atomic Operations- Dokumenten ( hier ):

MySQL Server (Version 3.23-max und alle Versionen 4.0 und höher) unterstützt Transaktionen mit den Transaktionsspeicher-Engines InnoDB und BDB. InnoDB bietet vollständige ACID-Konformität. Siehe Kapitel 14, Speichermotoren. Informationen zu InnoDB-Unterschieden zu Standard-SQL in Bezug auf die Behandlung von Transaktionsfehlern finden Sie in Abschnitt 14.2.11, „InnoDB-Fehlerbehandlung“.

Die anderen nicht-transaktionalen Speicher-Engines in MySQL Server (wie MyISAM) folgen einem anderen Paradigma für die Datenintegrität, das als "atomare Operationen" bezeichnet wird. In transaktionaler Hinsicht arbeiten MyISAM-Tabellen effektiv immer im Autocommit = 1-Modus. Atomoperationen bieten häufig eine vergleichbare Integrität bei höherer Leistung.

Da MySQL Server beide Paradigmen unterstützt, können Sie entscheiden, ob Ihre Anwendungen durch die Geschwindigkeit atomarer Operationen oder die Verwendung von Transaktionsfunktionen am besten bedient werden. Diese Auswahl kann pro Tabelle getroffen werden.

dmmd
quelle
Dies gilt für DML und nicht immer für DDL.
Jewgenij Afanasjew
4

Wenn eine Ausnahme auftritt, wird die Transaktion automatisch zurückgesetzt.

Laravel Basic Transaktionsformat

    try{
    DB::beginTransaction();

    /* 
    * SQL operation one 
    * SQL operation two
    ..................     
    ..................     
    * SQL operation n */


    DB::commit();
   /* Transaction successful. */
}catch(\Exception $e){       

    DB::rollback();
    /* Transaction failed. */
}
srmilon
quelle