MySQL和TiDB RR隔离级别下的不一致问题

【 TiDB 使用环境】测试
【 TiDB 版本】v6.5.0
【复现路径】
在TiDB创建如下表并插入数据

CREATE DATABASE test;
CREATE TABLE test.student (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);
INSERT INTO student (name) VALUES ('John');
INSERT INTO student (name) VALUES ('Alice');
INSERT INTO student (name) VALUES ('Bob');
INSERT INTO student (name) VALUES ('Emma');

随后开启两个会话,按照如下顺序测试

Process1 Process2
use test;
start transaction;
use test;
start transaction;
select name from student s where id=2 for update;
select name from student s where id=2 for update;
update student set name = ‘Eric’ where id = 1;
commit;
select * from student where id = 1;
commit;

【遇到的问题:问题现象及影响】
Process2的select * from student where id = 1;读取到的仍然是John而非Eric
而同样的操作在MySQL上执行时,Process2的select * from student where id = 1;读取到的却是Eric
该问题是因为MySQL的延迟加载导致的

begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作InnoDB表的语句(第一个快照读语句),事务才真正启动。如果你想要马上启动一个事务,可以使用start transaction with consistent snapshot 这个命令。

但这样无疑会导致TiDB和MySQL在某些场景下结果不同
想问一下能否调整为和MySQL一致,另外这是否会导致某些原本适配MySQL的代码出现问题?我个人理解是有可能的,因为之前MySQL是可以把锁后更新的值同步给下一个锁的获取者的,但在TiDB上着就不行了

你设置了事务隔离级别没

隔离级别就是默认的RR,MySQL和TiDB的隔离级别都是RR,但我理解这两者的RR不太一致,TiDB是以事务开始为准,而MySQL是以第一次InnoDB读语句为准

tidb改成rc级别,那个rr级别我觉得没啥用

改成RC级别会出现某些并发问题吗?我理解RC和RR之间的区别比较大

不会,据我和tidb厂商工程师交流,一般都是跑rc模式。

另外我也是不是很理解rr存在的意义是什么


看官方文档对于RR隔离级别的描述,tidb的显示是没有问题的,我理解应该是事务开始的时候获取了tso ,已tso 对应的数据为准

在mysql环境中的 是不是可以理解为rr级别下的当前读和快照读的区别,如果是当前读的情况下应该是和tidb 保持一致的,当前读应该是读取的最新数据,不知道我理解的对不对

设置了事务隔离级别了吗

隔离级别是RR,就会这样,因为你是在一个未完成的事务中去读取的

RR隔离级别是MySQL默认的,从近十多年的数据库经验看,这个隔离级别会有很多问题,特别是再遇到INDEX GAP LOCK的问题【通过辅助索引更新数据场景】,所以建议使用RC隔离级别比较好

甚至mysql新的版本rr存在意义也不明

有些业务确实在可重复读的需求,所以还得看业务,如果业务层能兼容的话,选择RC是最好的选择,你可以看看商业数据库ORACLE,DB2就知道了

90%的业务场景,rc就满足了,还没听说那个业务因为Oracle只支持rc不用oracle的

2 个赞

非常有道理

分析的不错

tidb和mysql rr的区别https://docs.pingcap.com/zh/tidb/v6.5/transaction-isolation-levels#与-mysql-可重复读隔离级别的区别

早期因Mysql的binlog格式问题,如果工作在RC隔离级别下,Mysql可能导致主从数据不一致,RR模式下没问题,所以默认就RR了

很早的问题了,早就解决了

说是这样的,默认就RR就没改了