Les données validées MySQL ne sont pas vues pour sélectionner la requête


13

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 tableest un InnoDB tableet les valeurs par défaut comme auto commitet le niveau d'isolement en lecture répétable sont définis.

Problème : un Insertse produit à l'intérieur d'une transaction et un selectqui lit les mêmes données insérées ne voit pas les données. Les selectcourses après le insertet après la inserttransaction 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 insertsfont 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 commitpas sur le fil 40? Puisqu'il n'a pas l'ID de thread.

Pour résumer, j'ai deux questions.

  1. Est-ce que le BEGINdans le binlog est avant le INSERT 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é.

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


Vous l'avez étiqueté 5.5, mais mentionné 5.6; Lequel est-ce? La réplication est-elle impliquée?
Rick James

@RickJames désolé, il s'agit du 5.6.19. J'ai mis à jour la question avec l'exemple de la requête et du journal bin. De plus, aucune réplication n'est impliquée. J'ai activé le journal bin uniquement après avoir remarqué le problème pour le déboguer. Merci
Ahmed Aeon Axan

Merci, ça aide. Je ne vois pas de BEGINou START TRANSACTION. Utilisez-vous plutôt autocommit=0? (Je préfère commencer ... s'engager; cela clarifie l'étendue de la transaction.)
Rick James

Ainsi, le framework (Spring) gère les transactions et il définit généralement autocommit = 0 et valide à la fin. Je suppose que nous ne voyons pas autocommit = 0 ici car la connexion était déjà dans cet état.
Ahmed Aeon Axan

Réponses:


3

J'essaie de faire une hypothèse sur la deuxième question:

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

Les transactions sont gérées par Spring. Il serait donc possible qu'avant d'exécuter le selectressort ait levé une start transactionou qu'il ait déjà utilisé la connexion pour exécuter une autre requête.

Je démarre 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ù autocommitest définie 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)

Passez à session1 pour valider l'insertion.

session1> commit;

Maintenant, passez à nouveau à la session2:

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

Session2 ne peut pas voir la ligne qui vient d'être insérée. Si a commitest levé dans la session2, nous pouvons voir une nouvelle ligne insérée dans la 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 à ceci:

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 dans votre journal général si le connection_id 36 a été utilisé pour d'autres requêtes. Faites-nous savoir.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.