30 Stimmen

Wie kann man feststellen, dass eine Transaktion bereits begonnen wurde?

Ich verwende Zend_Db, um einige Daten innerhalb einer Transaktion einzufügen. Meine Funktion startet eine Transaktion und ruft dann eine andere Methode auf, die ebenfalls versucht, eine Transaktion zu starten und natürlich fehlschlägt (ich verwende MySQL5). Die Frage ist also - wie kann ich erkennen, dass die Transaktion bereits gestartet wurde? Hier ist ein Beispiel für Code:

       try {
                    Zend_Registry::get('database')->beginTransaction();

                    $totals = self::calculateTotals($Cart);
                    $PaymentInstrument = new PaymentInstrument;
                    $PaymentInstrument->create();
                    $PaymentInstrument->validate();
                    $PaymentInstrument->save();

                    Zend_Registry::get('database')->commit();
                    return true;

            } catch(Zend_Exception $e) {
                    Bootstrap::$Log->err($e->getMessage());
                    Zend_Registry::get('database')->rollBack();
                    return false;
            }

Innerhalb von PaymentInstrument::create gibt es eine weitere beginTransaction-Anweisung, die die Ausnahme erzeugt, die besagt, dass die Transaktion bereits gestartet wurde.

1voto

Dens Punkte 429

Sie können Ihren Code auch wie folgt schreiben:

try {
    Zend_Registry::get('database')->beginTransaction();
} 
catch (Exception $e) { }

try {
    $totals = self::calculateTotals($Cart);

    $PaymentInstrument = new PaymentInstrument;
    $PaymentInstrument->create();
    $PaymentInstrument->validate();
    $PaymentInstrument->save();

    Zend_Registry::get('database')->commit();
    return true;
} 
catch (Zend_Exception $e) {
    Bootstrap::$Log->err($e->getMessage());
    Zend_Registry::get('database')->rollBack();
    return false;
}

1voto

Stephen Adelakun Punkte 714

Diese Diskussion ist schon ziemlich alt. Wie bereits erwähnt, können Sie dies in Ihrer Anwendung tun. PHP hat seit Version 5 >= 5.3.3 eine Methode, um festzustellen, ob man sich mitten in einer Transaktion befindet. PDP::inTransaction() gibt true oder false zurück. Link http://php.net/manual/en/pdo.intransaction.php

0voto

Gregory Magarshak Punkte 1845

In webbasiertem PHP werden Skripte fast immer während einer einzigen Webanfrage aufgerufen. Was Sie in diesem Fall wirklich tun möchten, ist, eine Transaktion zu starten und sie unmittelbar vor dem Ende des Skripts zu übertragen. Wenn etwas schief geht, lösen Sie eine Ausnahme aus und machen das Ganze rückgängig. Etwa so:

wrapper.php:

try {
   // start transaction
   include("your_script.php");
   // commit transaction
} catch (RollbackException $e) {
   // roll back transaction
}

Etwas komplexer wird die Situation beim Sharding, bei dem Sie möglicherweise mehrere Verbindungen öffnen. Sie müssen sie zu einer Liste von Verbindungen hinzufügen, bei denen die Transaktionen am Ende des Skripts übertragen oder zurückgenommen werden sollen. Beachten Sie jedoch, dass Sie im Falle von Sharding ohne eine globale Mutex für Transaktionen nicht ohne weiteres in der Lage sind, eine echte Isolierung oder Atomisierung gleichzeitiger Transaktionen zu erreichen, da ein anderes Skript seine Transaktionen an die Shards übermitteln könnte, während Sie Ihre übermitteln. Sie sollten sich jedoch MySQLs verteilte Transaktionen .

0voto

siva kiran Punkte 36

Verwenden Sie zend profiler um begin als Abfragetext und Zend_Db_Prfiler::TRANSACTION als Abfragetyp ohne commit oder rollback als Abfragetext zu sehen. (Unter der Annahme, dass es keine ->query("START TRANSACTION") gibt und zend profiler in Ihrer Anwendung aktiviert ist)

0voto

Zac Imboden Punkte 751

Ich stimme nicht mit Bill Karwins Einschätzung überein, dass es verrückt ist, die begonnenen Transaktionen zu verfolgen, obwohl ich dieses Wort mag.

Ich habe eine Situation, in der ich Ereignisbehandlungsfunktionen habe, die von einem nicht von mir geschriebenen Modul aufgerufen werden könnten. Meine Event-Handler erstellen eine Menge von Datensätzen in der Datenbank. Ich muss auf jeden Fall einen Rollback durchführen, wenn etwas nicht korrekt übergeben wurde oder fehlt oder wenn etwas schief läuft. Ich kann nicht wissen, ob der Code des externen Moduls, der den Event-Handler auslöst, DB-Transaktionen verarbeitet, da der Code von anderen Leuten geschrieben wurde. Ich habe keine Möglichkeit gefunden, die Datenbank abzufragen, um zu sehen, ob eine Transaktion im Gange ist.

Ich zähle also mit. Ich verwende CodeIgniter, die seltsame Dinge zu tun scheint, wenn ich es bitten, mit verschachtelten db-Transaktionen (z.B. Aufruf es trans_start() Methode mehr als einmal) zu starten. Mit anderen Worten, ich kann nicht einfach trans_start() in meinen Event-Handler einfügen, denn wenn eine externe Funktion ebenfalls trans_start() verwendet, werden Rollbacks und Commits nicht korrekt ausgeführt. Es besteht immer die Möglichkeit, dass ich noch nicht herausgefunden habe, wie ich diese Funktionen richtig verwalte, aber ich habe viele Tests durchgeführt.

Alles, was meine Event-Handler wissen müssen, ist, ob eine DB-Transaktion bereits von einem anderen Modul initiiert wurde, das sie aufruft. Wenn ja, wird keine weitere neue Transaktion gestartet und auch keine Rollbacks oder Commits berücksichtigt. Es vertraut darauf, dass wenn eine externe Funktion eine DB-Transaktion initiiert hat, dann wird es auch Rollbacks/Commits behandeln.

Ich habe Wrapper-Funktionen für CodeIgniter's Transaktionsmethoden und diese Funktionen inkrementieren/dekrementieren einen Zähler.

function transBegin(){
    //increment our number of levels
    $this->_transBegin += 1;
    //if we are only one level deep, we can create transaction
    if($this->_transBegin ==1) {
        $this->db->trans_begin();
    }
}

function transCommit(){
    if($this->_transBegin == 1) {
        //if we are only one level deep, we can commit transaction
        $this->db->trans_commit();
    }
    //decrement our number of levels
    $this->_transBegin -= 1;

}

function transRollback(){
    if($this->_transBegin == 1) {
        //if we are only one level deep, we can roll back transaction
        $this->db->trans_rollback();
    }
    //decrement our number of levels
    $this->_transBegin -= 1;
}

In meiner Situation ist dies die einzige Möglichkeit, nach einer bestehenden Datenbank-Transaktion zu suchen. Und es funktioniert. Ich würde nicht sagen, dass "die Anwendung DB-Transaktionen verwaltet". Das ist in dieser Situation wirklich unwahr. Es wird lediglich geprüft, ob ein anderer Teil der Anwendung eine DB-Transaktion gestartet hat, um die Erstellung verschachtelter DB-Transaktionen zu vermeiden.

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