2016-05-20 6 views
1

Gibt es eine Möglichkeit, MySQL zu fragen, ob ich mich gerade in einer Transaktion befinde? Ich bin in einer interaktiven Sitzung von der Kommandozeile mysql Client, ich habe ein paar Transaktionen geöffnet und geschlossen, und jetzt sollte ich nicht in einer Transaktion sein, aber es tut so, als ob ich vielleicht bin. Wie überprüfe/überprüfe ich meinen Verbindungsstatus? Ich versuchte mein Glück und tippte SHOW TRANSACTION, aber so etwas gibt es nicht.Aktuell aktive Transaktion (en) in mysql anzeigen

Due Diligence:

ich bei anderen Fragen haben gesucht (und der transaction documentation, natürlich), und keine Antwort gefunden haben. This question behandelt die Wiederherstellung von Transaktionen, nachdem eine Verbindung gelöscht wurde. This one scheint zu fragen, ob Transaktionen in anderen Threads aktiv sind. Ich möchte sehen, ob meine Verbindung in einer Transaktion ist.

Ich versuchte auch SELECT @@AUTOCOMMIT FROM DUAL, wie vorgeschlagen here. Aber es hilft nicht: Wenn ich eine Transaktion starte, ändert sich ihr Wert nicht, sondern bleibt 1 ("autocommit enabled").

Antwort

1

information_schema. innodb_trxwird sagen Ihnen, wenn Sie in einer Transaktion sind innerhalb InnoDB. Wenn Sie noch nicht auf Tabellen zugegriffen oder explizit einen Lesesnapshot erstellt haben, befinden Sie sich nur in einer Transaktion in MySQL (die "Server-Schicht") und nicht in InnoDB (der "Speicher-Engine-Schicht").).

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID(); 
+----------+ 
| count(1) | 
+----------+ 
|  0 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> START TRANSACTION; 
Query OK, 0 rows affected (0.00 sec) 

Okay, ich habe nicht vor, aber jetzt Ich habe eine Transaktion, und ...

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID(); 
+----------+ 
| count(1) | 
+----------+ 
|  0 | 
+----------+ 
1 row in set (0.00 sec) 

... es gibt noch nichts für meine aktuellen CONNECTION_ID() in innodb_trx.

Aber, wenn ich oder gerade von einer InnoDB-Tabelle schreiben lesen ...

mysql> SELECT COUNT(1) FROM t1; 
+----------+ 
| COUNT(1) | 
+----------+ 
|  301 | 
+----------+ 
1 row in set (0.00 sec) 

... jetzt kann ich meine Transaktion sehen, weil InnoDB sich dessen bewusst ist.

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID(); 
+----------+ 
| count(1) | 
+----------+ 
|  1 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> ROLLBACK; 
Query OK, 0 rows affected (0.00 sec) 

Lassen Sie uns sicherstellen, dass es weg ist ...

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID(); 
+----------+ 
| count(1) | 
+----------+ 
|  0 | 
+----------+ 
1 row in set (0.00 sec) 

Nun sagen Sie den Server mit dem Speicher-Engine zu sagen, dass meine MVCC Ansicht beginnt jetzt, nicht später:

mysql> START TRANSACTION WITH CONSISTENT SNAPSHOT; 
Query OK, 0 rows affected (0.00 sec) 

Hinweis dass mir das eigentlich keinen "konsistenten" Schnappschuss gibt, wenn mein Isolationslevel es nicht erlaubt. Aber es reicht, dass InnoDB jetzt weiß, dass ich hier bin.

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID(); 
+----------+ 
| count(1) | 
+----------+ 
|  1 | 
+----------+ 
1 row in set (0.00 sec) 

... und InnoDB erfährt sofort von der Transaktion.


Jetzt gibt es eine andere Möglichkeit zu bestimmen, ob Sie gerade in einer Transaktion sind. Oder, richtiger, ich sollte sagen, dass es eine andere Möglichkeit gibt zu bestimmen, dass Sie nicht in einer Transaktion gerade jetzt sind.

Ich verwende dies für gespeicherte Prozeduren, die innerhalb einer Transaktion ausgeführt werden müssen - der Aufrufer ist verantwortlich für das Starten und Festschreiben oder Zurückrollen, und die Prozedur wird nicht ausgeführt, wenn es keine aktive Transaktion gibt. Wie?

Die Prozedur ruft eine andere Prozedur auf, die im Hintergrund erfolgreich ist, wenn ich eine Transaktion habe, aber eine Ausnahme auslöst, wenn nicht. Wenn eine Prozedur eine zweite Prozedur aufruft und die zweite Prozedur eine Ausnahme auslöst, wird die erste Prozedur mit der gleichen Ausnahme beendet, es sei denn, die erste Prozedur hat eine HANDLER installiert, um den Fehler abzufangen.

Also, wenn meine äußere Prozedur diese Prozedur aufruft, wenn es eine Transaktion aktiv ist, geschieht nichts, und die äußere Prozedur ausgeführt werden darf:

mysql> START TRANSACTION; 
Query OK, 0 rows affected (0.00 sec) 

mysql> CALL mysql.require_transaction; 
Query OK, 0 rows affected (0.00 sec) 

^^^ diese ^^^ ist, was ich in der Nähe zu tun der Anfang, innerhalb meiner gespeicherten Prozeduren, die nur ausgeführt werden müssen, wenn sie innerhalb einer Transaktion aufgerufen werden.

Kein Fehler, wir waren in einer Transaktion. Wenn es sich um eine andere Prozedur gehandelt hätte, hätte diese Prozedur einfach zur nächsten Anweisung weitergegangen.

Aber wenn wir meinen require_transaction Prozedur aufrufen und wir sind nicht in einer Transaktion:

mysql> ROLLBACK; 
Query OK, 0 rows affected (0.00 sec) 

mysql> CALL mysql.require_transaction; 
ERROR 1644 (42000): you must have an active database transaction before attempting 
this operation 

Ordentlich. Wir stürzen unseren Anrufer mit einer benutzerdefinierten Fehlermeldung ab. Wie?

DELIMITER $$ 
CREATE PROCEDURE `mysql`.`require_transaction`() 
BEGIN 

-- test the session's transactional status, 
-- throwing an exception if we aren't in a transaction, 
-- but finishing successfully if we are 

DECLARE CONTINUE HANDLER 
     FOR 1305 
     SIGNAL SQLSTATE '42000' 
     SET MESSAGE_TEXT = 'you must have an active database transaction before attempting this operation'; 

SAVEPOINT `we created to be sure you were in a transaction`; 
ROLLBACK TO SAVEPOINT `we created to be sure you were in a transaction`; 

END $$ 
DELIMITER ; 

Das hat für meine lange Zeit Abhilfe gewesen, was ich glaube, dass eine erhebliche Kontrolle bei der Gestaltung von MySQL zu sein - die offensichtlichen Unfähigkeit endgültig aus der SQL-Schnittstelle, um zu bestimmen, ob Sie sich gerade in einer Transaktion . Hier ist, warum dies funktioniert:

  • ein SAVEPOINT anlegen und sofort rollen zurück, um es im Wesentlichen ein no-op. Solange es nicht schon einen aktiven Savepoint mit dem gleichen Namen gab, kein Schaden, kein Foul. Ich habe den sehr unwahrscheinlichen Namen we created to be sure you were in a transaction für meine SAVEPOINT verwendet.

  • Das Erstellen einer SAVEPOINT kann nicht durchgeführt werden, wenn Sie nicht in einer Transaktion sind, aber dies tatsächlich im Hintergrund fehlschlägt.

  • Rollback zurück zu einem SAVEPOINT, das nicht existiert, wird Fehler 1305, also wenn Sie nicht in einer Transaktion sind, wurde es nicht erstellt, und jetzt wird es nicht existieren, und es ist Ihr Fehler. Wenn Sie sich in einer Transaktion befinden, wird die SAVEPOINT erstellt und dann freigegeben, Ihre Transaktion so belassen, wie es war.

mysql> ROLLBACK TO SAVEPOINT `we created to be sure you were in a transaction`; 
ERROR 1305 (42000): SAVEPOINT we created to be sure you were in a transaction does not exist 
mysql> 

Hahahaha, das ist ein spiffy Hack. Jetzt sehen Sie, warum ich den Namen verwendet habe, den ich für meinen falschen Sicherungspunkt verwendet habe - "existiert nicht" wird an den Objektnamen angehängt, um die Fehlermeldung zu bilden.

auf MySQL 5.1, die nicht SIGNAL hat, meine require_transaction gespeicherte Prozedur beendet einfach mit dem nativen Fehler, die fast sinnvoll ... oder zumindest sinnvoll genug ist, dass jemand das DBA fragen wird kommen (me) was es bedeutet.

Um es schöner zu machen, in MySQL Server 5.5 und höher, fangen wir Fehler 1305 mit einem CONTINUE HANDLER, mit dem wir unsere eigene benutzerdefinierte Fehlermeldung mit SIGNAL setzen können.

Die Einstellung und dann das sofortige Zurückrollen zu einem Sicherungspunkt ist ein tragisch hackiger aber todsicherer Weg, um festzustellen, ob Sie in einer Transaktion sind.

+1

Danke! SQL ist nicht auf interaktive Nutzung oder menschliche Fehler ausgerichtet (so ziemlich das Gleiche), oder? Da mein Anwendungsfall die interaktive Konsole ist, versuche "ein SAVEPOINT zu erstellen und zurück zu rollen" ist eine ziemlich gute Lösung für meine Bedürfnisse. (Vielleicht sollten Sie es oben als TL hinzufügen; DNR-Intro :-) – alexis

+0

Ich nehme diesen Vorschlag unter Beratung, und überlege ein wenig Refactoring der Antwort. Vielen Dank. :) –

1

Haben Sie versucht, 22.31.4 The INFORMATION_SCHEMA INNODB_TRX Table zu verwenden?

SELECT 
    COUNT(`trx_id`) `inTransaction?` 
FROM 
    `INFORMATION_SCHEMA`.`INNODB_TRX` 
WHERE 
    `trx_mysql_thread_id` = CONNECTION_ID(); 
+0

Ich habe gerade, und es gibt mir "0" vor und nach dem ich eine Transaktion starten. – alexis

+0

Auch erwähnenswert: Es erfordert die Berechtigung "PROCESS", also ist es nicht immer eine Option (auch wenn Sie es beheben können). – alexis

+0

Es * sieht * wie es sollte funktionieren, obwohl. Seltsam. Ich habe die Tabelle "innodb_trx" überprüft und sie bleibt vollständig leer, nachdem ich 'START TRANSACTION' aufgerufen habe. (Ich habe jedoch keine Änderungen an der db vorgenommen.) – alexis