tidb并发的时候拿的数据不是最新的

【 TiDB 使用环境】生产环境 /测试
【 TiDB 版本】v5.4.2
【复现路径】做过哪些操作出现的问题
现有A和B两个业务:
A业务开启事务有sql语句如下:SELECT * from t1 where id=1 FOR UPDATE ;

UPDATE t1 SET num = num-1 WHERE id=1;

B业务在事务里面同样有一条查询的sql加上SELECT * from t1 where id=1 FOR UPDATE ;

同时或依次执行A、B两个业务。

【遇到的问题:问题现象及影响】
当A业务还没执行完毕时,B业务会阻塞等待。当A业务完成且事务提交后,B业务会继续往下跑,但是B业务里面的SELECT * from t1 where id=1 FOR UPDATE 取到的数据是A业务修改前的数据。

反复测试得到结果是:其中一个事务提交释放锁之后,另一个事务再查,查的还是旧数据。
这样造成很多数据问题了。

请问下其中的理由,以及有什么解决方案?
【资源配置】
【附件:截图/日志/监控】

这个问题跟MVCC相关
A和B事务启动,两个事务获取的数据版本是执行第一个sql语句时的数据版本
如果B事务想要在A事务的基础上查询or修改数据,那么B事务应该是在A事务commit后再开启事务

本来就是这样设计的呀

好解决,你没有修改事务级别吧,tidb默认事务级别rr,改成rc级别。
默认的rr级别,a事务开始后,b事务再开始,a事务改动b事务是看不到的

1 个赞

不符合这种幻读的情况,如果有提交了再开启另外的事务,那lock岂不是没用了。

大佬这种情况应该如何解决?

目前是使用默认的,如果rc级别会不会有什么其他影响?

没啥影响,rc性能还好点。rr隔离没啥用,拿不到其他事务commit后的数据,mysql用rr是历史问题,和binlog有关,Oracle用的rc级别

2 个赞

可是mysql的可重复读,也不会出现这个问题啊。

1 个赞

set global transaction_isolation=‘READ-COMMITTED’;
就可以了

我研究过,两个rr不一样,tidb是a事务开始,b事务再开始就看不到a的改动了,mysql是a事务做了修改开始前b事务开始还是能看到a事务改动。

我理解错了,for update是获取的当前最新的数据
B事务应该是拿到A事务提交后的数据
这个情况不是幻读
我这边测试了一下,是拿到了最新的数据,不知道大佬的TiDB版本、隔离级别是什么样的
TiDB版本:v4.0.8
隔离级别:REPEATABLE-READ

1 个赞

1 个赞

REPEATABLE-READ
TiDB版本:v5.4.2
稍等我按你的这个脚本测试下贴个图

看业务需求,RR,乐观锁,悲观锁,选一个

测试有结果了吗,我测了下7.1版本 for upate拿到的是最新值,不加for update就是旧值

有销售,库存,金额业务的需求,一般怎么选好?

TiDB版本:v5.4.2
隔离级别:REPEATABLE-READ
B事务会阻塞,直到A事务提交拿提交后的数据。

请问下,如果A事务有t1、t2表;B事务有t1、t2表。也是在刚才的场景下,对t1表加for update,更新t1和t2表。都B事务拿t2表是改动前还是后的数据?

那符合预期的呀,for update就是当前读,是会拿到最新的数据
前面你的问题是,事务1更新后,事务2for update查询到的是旧数据,那么这个问题就不存在了