Kontext: Das verwendete Framework ist Spring und alle Abfragen werden mit JdbcTemplate ausgeführt. MySQL Server Version ist 5.6.19. Das table
ist ein InnoDB table
und Standard auto commit
und die Isolationsstufe Wiederholbares Lesen ist eingestellt.
Problem : Ein Insert
Ereignis innerhalb einer Transaktion und ein select
Ereignis, das dieselben eingefügten Daten liest, sieht die Daten nicht. Das select
läuft nach dem insert
und nach der insert
Transaktion 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'
insert
Erstaunlicherweise 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 inserts
sind 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 commit
nicht am Faden 40? Da es nicht die Thread-ID hat.
Zusammenfassend habe ich zwei Fragen.
BEGIN
Befindet sich das im Binlog vor demINSERT 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.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.
quelle
BEGIN
oderSTART TRANSACTION
. Verwenden Sie stattdessenautocommit=0
? (Ich bevorzuge begin ... commit; es macht den Umfang der Transaktion klar.)Antworten:
Ich versuche eine Hypothese über die zweite Frage zu machen:
Transaktionen werden von Spring verwaltet. Es wäre also möglich, dass die
select
Feder vor dem Laufen einen ausgelöst hatstart transaction
oder 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
:Ich erstelle eine neue Sitzung, Sitzung2, wobei
autocommit
0 festgelegt ist. In dieser neuen Sitzung wird implizit eine Transaktion gestartet, wenn eine Auswahl ausgeführt wird.Wechseln Sie zu Sitzung1, um die Einfügung zu bestätigen.
Wechseln Sie nun erneut zu Sitzung2:
Session2 kann die gerade eingefügte Zeile nicht sehen. Wenn a
commit
in session2 ausgelöst wird, wird in session1 eine neue Zeile eingefügtDas allgemeine Protokoll sieht folgendermaßen aus:
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.
quelle