未看到 MySQL 提交的数据来选择查询

Ahm*_*xan 13 mysql transaction java mysql-5.6

上下文:使用的框架是 Spring,所有查询都使用 JdbcTemplate 运行。Mysql Server 版本为 5.6.19。这table是一个InnoDB table和默认值,并且设置了auto commit隔离级别可重复读取。

问题Insert一个事务发生在一个事务中select,读取插入的相同数据的一个没有看到数据。在select运行后,insert之后的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/*!*/;
Run Code Online (Sandbox Code Playgroud)

查询日志

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'
Run Code Online (Sandbox Code Playgroud)

奇怪的是,First insert(249935389) 根本不应该是交易的一部分。它是一个单独的 API 调用,完全不相关。可能是春天将它与事务混合在一起,或者我读错了日志?AFAIK 因为它在同一个线程上,所以它意味着插入在事务中。

接下来的两个inserts是事务的一部分,看起来像是提交了。(249936514)。现在选择查询(一般日志中的最后一个)在提交后运行并且它看不到数据。它返回 0 行。考虑到数据,这怎么会发生committed?或者是commit不是在线程40上?因为它没有线程ID。

总结一下,我有两个问题。

  1. BEGINbinlog 中的是否在之前INSERT INTO user_geo_loc(它不是事务的一部分),这是 spring/Jdbc 或 MySql 的一个错误,因为它知道这个事务已经提交(因为事务在它们已经提交时被写入 binlog)成功),因此永远不会回滚。

  2. 鉴于提交发生在选择之前(提交时间为 14:16:06,选择时间为 14:16:07),选择如何不返回事务插入的行?

这是非常令人困惑的。任何帮助,将不胜感激

注意:bin 和查询日志中的查询已被编辑以删除敏感信息。但查询的本质保持不变

编辑:使用详细示例更新了一般日志和查询日志。

小智 3

我尝试对第二个问题做一个假设:

假设提交发生在 select 之前(提交发生在 14:16:06,select 发生在 14:16:07),select 为何不返回事务插入的行?

事务由 Spring 管理。因此,在运行之前,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)
Run Code Online (Sandbox Code Playgroud)

我创建一个新会话 session2,其中autocommit设置为 0。在这个新会话中,运行选择时会隐式启动事务。

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)
Run Code Online (Sandbox Code Playgroud)

移至 session1 以提交插入。

session1> commit;
Run Code Online (Sandbox Code Playgroud)

现在再次转到 session2:

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

Session2 看不到刚刚插入的行。如果commit在 session2 中引发 a,我们可以看到在 session1 中插入新行

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

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

一般日志如下所示:

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
Run Code Online (Sandbox Code Playgroud)

第一行与会话 2 相关。这是会话 2 打开事务的时间。

我不知道你的情况是否是这样。如果connection_id 36用于其他查询,您可以检查您的常规日志。让我们知道。