web-dev-qa-db-ja.com

MySQLコミットされたデータがクエリの選択に表示されない

コンテキスト:使用されるフレームワークはSpringであり、すべてのクエリはJdbcTemplateで実行されます。 Mysql Serverのバージョンは5.6.19です。 tableInnoDB tableであり、デフォルトはauto commitのようであり、分離レベルrepeatable-readが設定されています。

問題Insertがトランザクション内で発生し、挿入された同じデータを読み取るselectがデータを認識しません。 selectは、afterinsertを実行した後、insertトランザクションがcommitedを実行した後に実行されます。

Mysqlでbinログと一般的なログを有効にしました。以下の関連ログ

ビンログ:

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/*!*/;

クエリログ

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'

不思議なことに、最初のinsert(249935389)はトランザクションの一部ではありません。これは別個のAPI呼び出しであり、完全に無関係です。それはトランザクションと春の混合である可能性がありますか、それともログを間違って読んでいますか? AFAIKは同じスレッド上にあるため、挿入がトランザクション内にあることを意味します。

次の2つのinsertsはトランザクションの一部であり、コミットするように見えます。 (249936514)。これで、選択クエリ(一般ログの最後のクエリ)がコミット後に実行され、データが表示されなくなりました。 0行を返します。データがcommittedであることを考慮して、これはどのように起こりますか?または、commitはスレッド40にありませんか?スレッドIDがないので。

要約すると2つの質問があります。

  1. Binlog内のBEGININSERT INTO user_geo_loc(トランザクションの一部ではない)の前にありますか?これは、このトランザクションがすでにコミットされていることを知っているため、これはスプリング/ JdbcまたはMySqlのバグです(トランザクションはbinlogに書き込まれるため、成功しているため)ロールバックされることはありません。

  2. コミットが選択の前に発生すると(コミットは14:16:06で、選択は14:16:07です)、トランザクションによって挿入された行が選択によって返されないのはなぜですか。

これは非常に困惑しています。どんな助けでもいただければ幸いです

注:ビンとクエリログの両方のクエリは、機密情報を削除するために編集されています。ただし、クエリの本質は変わりません

編集:一般的なログと詳細な例を含むクエリログで更新されました。

13
Ahmed Aeon Axan

私は2番目の質問について仮説を立てようとします。

コミットが選択の前に発生すると(コミットは14:16:06で、選択は14:16:07です)、トランザクションによって挿入された行が選択によって返されないのはなぜですか。

トランザクションはSpringによって管理されます。したがって、実行前にselectスプリングがstart transactionを発生させたか、別のクエリを実行するためにすでに接続を使用している可能性があります。

テーブルへの挿入をシミュレートする最初のセッションを開始します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)

autocommitが0に設定されている新しいセッションsession2を作成します。この新しいセッションでは、選択の実行時にトランザクションが暗黙的に開始されます。

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)

挿入をコミットするには、session1に移動します。

session1> commit;

ここで再びセッション2に移動します。

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

セッション2は、挿入されたばかりの行を見ることができません。 commitがsession2で発生した場合、session1に挿入された新しい行を確認できます

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

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

一般的なログは次のようになります。

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

最初の行はセッション2に関連しています。セッション2がトランザクションを開いたときです。

これがあなたのケースで何が起こるかわかりません。他のクエリにconnection_id 36が使用されたかどうかを一般ログで確認できます。お知らせください。

3
Giovanni