Contexte: Le cadre utilisé est le printemps et toutes les requêtes sont exécutées avec JDBCTemplate. La version Server MySQL est 5.6.19. Le table
est un InnoDB table
et par défaut comme auto commit
et niveau d'isolement, lecture répétable est défini.
problème: Un Insert
arrive à l'intérieur d'une transaction et d'un select
qui lit les mêmes données insérées ne voit pas les données. Le select
exécute après le insert
et après la transaction insert
a commited
.
J'ai activé Bin Log ainsi que Général Connexion MySQL. Journaux pertinents ci-dessous
bin-journal:
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 de requête
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, le premier insert
(249935389) ne doit pas faire partie de la transaction du tout. C'est un appel d'API séparé et totalement sans rapport. Cela pourrait être le printemps en mélangeant avec la transaction ou je lis le bûche incorrect? Afaik depuis qu'il est sur le même thread, cela implique que l'insertion est dans la transaction.
Les deux suivants inserts
font partie de la transaction et on dirait qu'elle commet. (249936514). Maintenant, la requête SELECT (Dernière de journalisation générale) s'exécute après la commission et cela ne voit pas les données. Il retourne 0 rangées. Comment cela peut-il arriver en considérant que les données sont committed
? Ou est le commit
non sur le fil 40? Puisqu'il n'a pas l'identifiant de thread.
Pour résumer, j'ai deux questions.
Est-ce que le BEGIN
dans le binlog étant avant le INSERT INTO user_geo_loc
(qui ne fait pas partie de la transaction), est-ce qu'un bogue avec Spring/JDBC ou MySQL le fait-il simplement, car il sait que cette transaction s'est déjà engagée (comme les transactions sont écrites à Binlog quand elles ont réussi) et ne serait donc jamais être roulés.
Compte tenu de la validation avant que le Select (Select est à 14:16:06 et Select est à 14:16:07) Comment est-ce que le SELECT ne renvoie pas la ligne insérée par la transaction?
Ceci est extrêmement perplexe. Toute aide serait appréciée
Remarque: les requêtes dans le journal des bacs et de la requête ont été modifiées pour supprimer les informations sensibles. Mais l'essence des requêtes reste la même
Edit: mise à jour avec le journal général et le journal de requête avec un exemple détaillé.
J'essaie de faire une hypothèse sur la deuxième question:
Compte tenu de la validation avant que le Select (Select est à 14:16:06 et Select est à 14:16:07) Comment est-ce que le SELECT ne renvoie pas la ligne insérée par la transaction?
Les transactions sont gérées au printemps. Il serait donc possible qu'avant d'exécuter le select
printemps a soulevé un start transaction
ou il a déjà utilisé la connexion pour exécuter une autre requête.
Je commence une première session où je simule un insert dans une table 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)
Je crée une nouvelle session, Session2, où autocommit
est défini sur 0. Dans cette nouvelle session, une transaction est implicitement démarrée lors de l'exécution d'une sélection.
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)
Déplacer vers Session1 pour commettre l'insert.
session1> commit;
Maintenant, déplacez à nouveau à Session2:
session2> select * from t;
+---+
| i |
+---+
| 1 |
+---+
1 row in set (0,00 sec)
Session2 ne peut pas voir la ligne juste insérée. Si un commit
est soulevé en session2, nous pouvons voir une nouvelle ligne insérée dans Session1
session2> commit
1 row in set (0,00 sec)
session2> select * from t;
+---+
| i |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0,00 sec)
Le journal général ressemble à:
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
La première ligne est liée à la session 2. C'est lorsque la session 2 ouvre la transaction.
Je ne sais pas si c'est ce qui se passe dans votre cas. Vous pouvez vérifier votre journal général si le Connection_ID 36 a été utilisé pour d'autres requêtes. Laissez-nous savoir.