web-dev-qa-db-fra.com

MySQL a commité les données non vues pour sélectionner la requête

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.

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

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

13
Ahmed Aeon Axan

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.

3
Giovanni