Kontekst: Używany jest framework Spring, a wszystkie zapytania są uruchamiane za pomocą JdbcTemplate. Wersja Mysql Server to 5.6.19. table
To InnoDB table
i domyślnie jak auto commit
i poziom izolacji powtarzalne odczytania jest ustawiony.
Problem : Insert
Występuje wewnątrz transakcji, a select
czytający te same wstawione dane nie widzi danych. W select
biegnie poinsert
i po insert
transakcja ma commited
.
Włączyłem dziennik bin oraz ogólny dziennik w mysql. Odpowiednie dzienniki poniżej
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/*!*/;
Dziennik zapytań
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'
Co ciekawe, First insert
(249935389) w ogóle nie powinien być częścią transakcji. Jest to osobne wywołanie API i całkowicie niezwiązane. Może to być wiosenne mieszanie go z transakcją lub źle czytam dziennik? AFAIK, ponieważ jest w tym samym wątku, oznacza to, że wstawka jest w transakcji.
Następne dwa inserts
są częścią transakcji i wygląda na to, że się zobowiązuje. (249936514). Teraz wybrane zapytanie (ostatnie w dzienniku ogólnym) działa po zatwierdzeniu i nie widzi danych. Zwraca 0 wierszy. Jak to się może stać, biorąc pod uwagę dane committed
? A może commit
nie ma nici 40? Ponieważ nie ma identyfikatora wątku.
Podsumowując, mam dwa pytania.
Czy
BEGIN
w binlogu znajdującym się przedINSERT INTO user_geo_loc
(który nie jest częścią transakcji), jest to błąd z spring / Jdbc lub MySql po prostu robi to, ponieważ wie, że transakcja już się dokonała (ponieważ transakcje są zapisywane w binlog, gdy mają udało się) i dlatego nigdy nie zostanie wycofany.Biorąc pod uwagę, że zatwierdzenie następuje przed wyborem (zatwierdzenie jest o 14:16:06, a wybranie o 14:16:07), w jaki sposób zaznaczenie nie zwraca wiersza wstawionego przez transakcję?
To jest bardzo kłopotliwe. Każda pomoc będzie mile widziana
Uwaga: Zapytania w bin i dzienniku zapytań zostały edytowane w celu usunięcia poufnych informacji. Ale istota zapytań pozostaje taka sama
Edycja: zaktualizowano ogólny dziennik i dziennik zapytań ze szczegółowym przykładem.
źródło
BEGIN
aniSTART TRANSACTION
. Czy zamiast tego używaszautocommit=0
? (Wolę zacząć ... zatwierdzić; to wyjaśnia zakres transakcji.)Odpowiedzi:
Próbuję postawić hipotezę dotyczącą drugiego pytania:
Transakcje są zarządzane przez Spring. Byłoby więc możliwe, że przed uruchomieniem
select
sprężyna podniosłastart transaction
lub wykorzystała połączenie do uruchomienia innego zapytania.Rozpoczynam pierwszą sesję, w której symuluję wstawkę do tabeli
t
:Tworzę nową sesję, session2, gdzie
autocommit
jest ustawiona na 0. W tej nowej sesji transakcja jest domyślnie rozpoczynana po uruchomieniu select.Przejdź do sesji 1, aby zatwierdzić wstawienie.
Teraz przejdź ponownie do session2:
Sesja2 nie widzi właśnie wstawionego wiersza. Jeśli
commit
w session2 zostanie podniesiony a, możemy zobaczyć nowy wiersz wstawiony w session1Ogólny dziennik wygląda następująco:
Pierwszy wiersz dotyczy sesji 2. To wtedy sesja 2 otwiera transakcję.
Nie wiem, czy tak się stało w twoim przypadku. Możesz sprawdzić w dzienniku ogólnym, czy identyfikator połączenia 36 został użyty do innych zapytań. Daj nam znać.
źródło