Von MySQL festgeschriebene Daten werden für die Auswahl der Abfrage nicht angezeigt

13

Kontext: Das verwendete Framework ist Spring und alle Abfragen werden mit JdbcTemplate ausgeführt. MySQL Server Version ist 5.6.19. Das tableist ein InnoDB tableund Standard auto commitund die Isolationsstufe Wiederholbares Lesen ist eingestellt.

Problem : Ein InsertEreignis innerhalb einer Transaktion und ein selectEreignis, das dieselben eingefügten Daten liest, sieht die Daten nicht. Das selectläuft nach dem insertund nach der insertTransaktion hat commited.

Ich habe sowohl das bin-Protokoll als auch das allgemeine Protokoll in MySQL aktiviert. Relevante Protokolle unten

bin-log:

SET TIMESTAMP=1438265764/*!*/;
BEGIN
/*!*/;
# at 249935389
#150730 14:16:04 server id 1  end_log_pos 249935606 CRC32 0xa6aca292    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265764/*!*/;
insert into user_geo_loc_latest(user_id, lat, lng) values(x,y,z) on duplicate key update lat=y, lng=z
/*!*/;
# at 249935606
#150730 14:16:06 server id 1  end_log_pos 249936255 CRC32 0x2a52c734    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265766/*!*/;
INSERT INTO table(txnid) VALUES ('885851438265675046')
/*!*/;
# at 249936255
#150730 14:16:06 server id 1  end_log_pos 249936514 CRC32 0x6cd85eb5    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265766/*!*/;
INSERT INTO table2(x) VALUES (y)
/*!*/;
# at 249936514
#150730 14:16:06 server id 1  end_log_pos 249936545 CRC32 0xceb9ec56    Xid = 9406873
COMMIT/*!*/;

Abfrageprotokoll

150730 14:16:04    40 Query ...
....
40 Query     select count(*) from table where txnid = '885851438265675046'
                   40 Query     select @@session.tx_read_only
                   40 Query     INSERT INTO table(txnid) VALUES ('885851438265675046')
                   40 Query     select @@session.tx_read_only
                   40 Query     INSERT INTO table2(x) values(y)
                   40 Query     commit
....
150730 14:16:07    36 Query     select pp.*, b.create_date from table pp left join bill b on pp.bill_id = b.bill_id where pp.txnid = '885851438265675046'

insertErstaunlicherweise sollte First (249935389) überhaupt nicht Teil der Transaktion sein. Es ist ein separater API-Aufruf und völlig unabhängig. Es könnte Frühling sein, der es mit der Verhandlung mischt, oder ich lese das falsche Protokoll? AFAIK, da es sich um denselben Thread handelt, der impliziert, dass sich die Einfügung in der Transaktion befindet.

Die nächsten beiden insertssind Teil der Transaktion und es sieht so aus, als ob sie festgeschrieben wurde. (249936514). Jetzt wird die Auswahlabfrage (letzte im allgemeinen Protokoll) nach dem Festschreiben ausgeführt und die Daten werden nicht angezeigt. Es werden 0 Zeilen zurückgegeben. Wie kann dies angesichts der Datenlage geschehen committed? Oder liegt das commitnicht am Faden 40? Da es nicht die Thread-ID hat.

Zusammenfassend habe ich zwei Fragen.

  1. BEGINBefindet sich das im Binlog vor dem INSERT INTO user_geo_loc(was nicht Teil der Transaktion ist), ist dies ein Fehler mit spring / Jdbc oder MySql, da bekannt ist, dass diese Transaktion bereits festgeschrieben wurde (da Transaktionen in das Binlog geschrieben werden, wenn sie festgeschrieben wurden) erfolgreich war) und würde daher niemals zurückgesetzt werden.

  2. Wenn das Festschreiben vor dem Auswählen erfolgt (Festschreiben ist um 14:16:06 Uhr und Auswählen ist um 14:16:07 Uhr), wie kommt es dann, dass das Festschreiben die von der Transaktion eingefügte Zeile nicht zurückgibt?

Das ist äußerst verwirrend. Jede Hilfe wäre dankbar

Hinweis: Die Abfragen im Bin und im Abfrageprotokoll wurden bearbeitet, um vertrauliche Informationen zu entfernen. Der Kern der Abfragen bleibt jedoch derselbe

Bearbeiten: Aktualisiert mit allgemeinem Protokoll und Abfrageprotokoll mit einem detaillierten Beispiel.

Ahmed Aeon Axan
quelle
Sie haben es mit 5.5 markiert, aber 5.6 erwähnt; welches ist es? Ist die Replikation beteiligt?
Rick James
@ RickJames Entschuldigung, es ist 5.6.19. Ich habe die Frage mit dem Beispiel sowohl aus dem Abfrage- als auch aus dem Bin-Protokoll aktualisiert. Es ist auch keine Replikation erforderlich. Ich habe das Bin-Protokoll erst aktiviert, nachdem ich das Problem beim Debuggen bemerkt hatte. Vielen Dank
Ahmed Aeon Axan
Danke, das hilft. Ich sehe kein BEGINoder START TRANSACTION. Verwenden Sie stattdessen autocommit=0? (Ich bevorzuge begin ... commit; es macht den Umfang der Transaktion klar.)
Rick James
Das Framework (spring) verwaltet also Transaktionen und setzt normalerweise autocommit = 0 und schreibt am Ende fest. Ich vermute, wir sehen hier kein Autocommit = 0, weil die Verbindung bereits in diesem Zustand war.
Ahmed Aeon Axan

Antworten:

3

Ich versuche eine Hypothese über die zweite Frage zu machen:

Wenn das Festschreiben vor dem Auswählen erfolgt (Festschreiben ist um 14:16:06 Uhr und Auswählen ist um 14:16:07 Uhr), wie kommt es dann, dass das Festschreiben die von der Transaktion eingefügte Zeile nicht zurückgibt?

Transaktionen werden von Spring verwaltet. Es wäre also möglich, dass die selectFeder vor dem Laufen einen ausgelöst hat start transactionoder die Verbindung bereits zum Ausführen einer anderen Abfrage verwendet hat.

Ich beginne eine erste Sitzung, in der ich eine Einfügung in eine Tabelle simuliere t:

session1> create table t (i int auto_increment primary key);
Query OK, 0 rows affected (0,32 sec)

session1> insert into t values();
Query OK, 1 row affected (0,00 sec)

session1> select * from t;
+---+
| i |
+---+
| 1 |
+---+
1 row in set (0,00 sec)

session1> start transaction;
Query OK, 0 rows affected (0,00 sec)

session1> insert into t values();
Query OK, 1 row affected (0,00 sec)

Ich erstelle eine neue Sitzung, Sitzung2, wobei autocommit0 festgelegt ist. In dieser neuen Sitzung wird implizit eine Transaktion gestartet, wenn eine Auswahl ausgeführt wird.

session2> set autocommit = 0;
Query OK, 0 rows affected (0,00 sec)

session2> select * from t;  -- this starts a transaction
+---+
| i |
+---+
| 1 |
+---+
1 rows in set (0,00 sec)

Wechseln Sie zu Sitzung1, um die Einfügung zu bestätigen.

session1> commit;

Wechseln Sie nun erneut zu Sitzung2:

session2> select * from t;
+---+
| i |
+---+
| 1 |
+---+
1 row in set (0,00 sec)

Session2 kann die gerade eingefügte Zeile nicht sehen. Wenn a commitin session2 ausgelöst wird, wird in session1 eine neue Zeile eingefügt

session2> commit
1 row in set (0,00 sec)

session2> select * from t;
+---+
| i |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0,00 sec)

Das allgemeine Protokoll sieht folgendermaßen aus:

150804 14:04:10     2 Query select * from t

150804 14:04:30     1 Query start transaction
150804 14:04:39     1 Query insert into t values ()
150804 14:04:44     1 Query commit
150804 14:04:51     2 Query select * from t

150804 14:05:07     2 Query commit
150804 14:05:10     2 Query select * from t

Die erste Zeile bezieht sich auf Sitzung 2. In Sitzung 2 wird die Transaktion geöffnet.

Ich weiß nicht, ob dies in Ihrem Fall der Fall ist. Sie können in Ihrem allgemeinen Protokoll überprüfen, ob die connection_id 36 für andere Abfragen verwendet wurde. Lass es uns wissen.

Giovanni
quelle