Contexte: Le framework utilisé est Spring et toutes les requêtes sont exécutées avec JdbcTemplate. La version de Mysql Server est 5.6.19. Le table
est un InnoDB table
et les valeurs par défaut comme auto commit
et le niveau d'isolement en lecture répétable sont définis.
Problème : un Insert
se produit à l'intérieur d'une transaction et un select
qui lit les mêmes données insérées ne voit pas les données. Les select
courses après le insert
et après la insert
transaction a commited
.
J'ai activé le journal bin ainsi que le journal général dans mysql. Journaux pertinents ci-dessous
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/*!*/;
Journal des requêtes
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'
Curieusement, First insert
(249935389) ne devrait pas du tout faire partie de la transaction. Il s'agit d'un appel d'API distinct et totalement indépendant. Cela pourrait être le printemps en le mélangeant avec la transaction ou je lis mal le journal? AFAIK puisque c'est sur le même thread, cela implique que l'insert est dans la transaction.
Les deux suivants inserts
font partie de la transaction et il semble que la transaction soit validée. (249936514). Maintenant, la requête de sélection (la dernière dans le journal général) s'exécute après la validation et elle ne voit pas les données. Il renvoie 0 lignes. Comment cela peut-il arriver compte tenu des données committed
? Ou n'est-ce commit
pas sur le fil 40? Puisqu'il n'a pas l'ID de thread.
Pour résumer, j'ai deux questions.
Est-ce que le
BEGIN
dans le binlog est avant leINSERT INTO user_geo_loc
(qui ne fait pas partie de la transaction), est-ce un bogue avec spring / Jdbc ou MySql le fait simplement car il sait que cette transaction a déjà été validée (car les transactions sont écrites dans binlog quand elles ont réussi) et ne serait donc jamais annulé.Étant donné que la validation se produit avant la sélection (la validation est à 14:16:06 et la sélection est à 14:16:07), comment se fait-il que la sélection ne renvoie pas la ligne insérée par la transaction?
C'est extrêmement déroutant. Toute aide serait appréciée
Remarque: Les requêtes dans le bac et le journal des requêtes ont été modifiées pour supprimer les informations sensibles. Mais l'essence des requêtes reste la même
Edit: mis à jour avec le journal général et le journal des requêtes avec un exemple détaillé.
BEGIN
ou START TRANSACTION
. Utilisez-vous plutôt autocommit=0
? (Je préfère commencer ... s'engager; cela clarifie l'étendue de la transaction.)