先说结论
执行begin之后并没有真的开启事务,事务开启是在第一次对数据表操作的时候。
场景还原
我们在把一张表接入binlog(MySQL的二进制日志文件)同步的时候,首次接入需要做下面这些操作:
- 全局读锁,所有人无法写入。因为读锁了,所以所有人无法改变现状,不能写入新的内容。
- 开启事务
- 读取binlog最后位置,记录后就可以增量从这里拉取
- 释放全局读锁
- 同步全量数据,因为在事务里面,我们读取的是一份不会发生变化的快照
整体解释以下,因为如果我们把一张表接入增量系统,就需要先全量初始化,但是如何界定增量全量对得上呢,就需要短时锁全表,进行获取binlog最后位置,开启事务保证当前状态不发生改变。
但是理想很丰满,现实我们测试便知。
测试过程
我们用两个账号分别建立数据库连接来模拟接入服务的连接和其他操作数据库连接的操作。
连接A:查看当前数据
连接A:开始上锁
给数据库上一个全局的读锁,上锁成功,返回OK
FLUSH TABLES WITH READ LOCK
连接A:开启事务
BEGIN
连接A:读取binlog最后位置
可以通过下面的语句获取binlog的最后位置
在大多数基于binlog实现增量同步更新的系统中,都支持通过MySQL的binlog指定位置开始消费的能力。
show master status;
连接B:修改数据
我们使用另外一个账号建立的连接修改其中一条数据,将id为2的数据从 “李四” 修改为 “赵九” 。
理论上将,连接A已经开启了事务,对本次修改应该不感知。
UPDATE `cdc_test`.`member` SET `username` = '赵九' WHERE `id` = 2;
连接A:查询全部内容
查询全部内容发现数据已经被修改
SELECT * FROM member
结论
在编写这个代码的时候,发现一直获取不到我们期望的表信息不变的结果。
最后发现,如果希望在后来的读取中读取快照内容,必须在加锁期间,读取数据触发事务开始。
所以,我们可以发现,InnoDB的事务并非从begin开始,而是我们第一次对表操作的时候开始的。