MySQL Zaangażowane dane nie są widoczne w celu wybrania zapytania

13

Kontekst: Używany jest framework Spring, a wszystkie zapytania są uruchamiane za pomocą JdbcTemplate. Wersja Mysql Server to 5.6.19. tableTo InnoDB tablei domyślnie jak auto commiti poziom izolacji powtarzalne odczytania jest ustawiony.

Problem : InsertWystępuje wewnątrz transakcji, a selectczytający te same wstawione dane nie widzi danych. W selectbiegnie poinsert i po inserttransakcja 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 insertssą 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 commitnie ma nici 40? Ponieważ nie ma identyfikatora wątku.

Podsumowując, mam dwa pytania.

  1. Czy BEGINw binlogu znajdującym się przed INSERT 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.

  2. 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.

Ahmed Aeon Axan
źródło
Oznaczyłeś to 5.5, ale wspomniałeś 5.6; który to jest? Czy wymagana jest replikacja?
Rick James
@RickJames przepraszam, jest 5.6.19. Zaktualizowałem pytanie o przykład z dziennika zapytań i bin. Poza tym nie ma potrzeby replikacji. Włączyłem dziennik bin dopiero po zauważeniu problemu w celu debugowania. Dzięki
Ahmed Aeon Axan
Dzięki, to pomaga. Nie widzę BEGINani START TRANSACTION. Czy zamiast tego używasz autocommit=0? (Wolę zacząć ... zatwierdzić; to wyjaśnia zakres transakcji.)
Rick James
Tak więc środowisko (wiosna) zarządza transakcjami i zwykle ustawia autocommit = 0 i zatwierdza na końcu. Zgaduję, że nie widzimy tutaj autocommit = 0, ponieważ połączenie było już w tym stanie.
Ahmed Aeon Axan

Odpowiedzi:

3

Próbuję postawić hipotezę dotyczącą drugiego pytania:

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ę?

Transakcje są zarządzane przez Spring. Byłoby więc możliwe, że przed uruchomieniem selectsprężyna podniosła start transactionlub wykorzystała połączenie do uruchomienia innego zapytania.

Rozpoczynam pierwszą sesję, w której symuluję wstawkę do tabeli 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)

Tworzę nową sesję, session2, gdzie autocommitjest ustawiona na 0. W tej nowej sesji transakcja jest domyślnie rozpoczynana po uruchomieniu select.

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)

Przejdź do sesji 1, aby zatwierdzić wstawienie.

session1> commit;

Teraz przejdź ponownie do session2:

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

Sesja2 nie widzi właśnie wstawionego wiersza. Jeśli commitw session2 zostanie podniesiony a, możemy zobaczyć nowy wiersz wstawiony w session1

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

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

Ogólny dziennik wygląda następująco:

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

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ć.

Giovanni
źródło