zhimadi
(Zhimadi)
2023 年6 月 30 日 08:08
1
【 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业务修改前的数据。
反复测试得到结果是:其中一个事务提交释放锁之后,另一个事务再查,查的还是旧数据。
这样造成很多数据问题了。
请问下其中的理由,以及有什么解决方案?
【资源配置】
【附件:截图/日志/监控】
xiexin
(荒岛)
2023 年6 月 30 日 08:14
3
这个问题跟MVCC相关
A和B事务启动,两个事务获取的数据版本是执行第一个sql语句时的数据版本
如果B事务想要在A事务的基础上查询or修改数据,那么B事务应该是在A事务commit后再开启事务
zhanggame1
(Ti D Ber G I13ecx U)
2023 年6 月 30 日 08:22
5
好解决,你没有修改事务级别吧,tidb默认事务级别rr,改成rc级别。
默认的rr级别,a事务开始后,b事务再开始,a事务改动b事务是看不到的
1 个赞
zhimadi
(Zhimadi)
2023 年6 月 30 日 08:22
6
xiexin:
那么B事务应该是在A事务commit后再开启事务
不符合这种幻读的情况,如果有提交了再开启另外的事务,那lock岂不是没用了。
zhimadi
(Zhimadi)
2023 年6 月 30 日 08:23
8
目前是使用默认的,如果rc级别会不会有什么其他影响?
zhanggame1
(Ti D Ber G I13ecx U)
2023 年6 月 30 日 08:25
9
没啥影响,rc性能还好点。rr隔离没啥用,拿不到其他事务commit后的数据,mysql用rr是历史问题,和binlog有关,Oracle用的rc级别
2 个赞
zhanggame1
(Ti D Ber G I13ecx U)
2023 年6 月 30 日 08:29
11
set global transaction_isolation=‘READ-COMMITTED’;
就可以了
zhanggame1
(Ti D Ber G I13ecx U)
2023 年6 月 30 日 08:31
12
我研究过,两个rr不一样,tidb是a事务开始,b事务再开始就看不到a的改动了,mysql是a事务做了修改开始前b事务开始还是能看到a事务改动。
xiexin
(荒岛)
2023 年6 月 30 日 10:14
13
我理解错了,for update是获取的当前最新的数据
B事务应该是拿到A事务提交后的数据
这个情况不是幻读
我这边测试了一下,是拿到了最新的数据,不知道大佬的TiDB版本、隔离级别是什么样的
TiDB版本:v4.0.8
隔离级别:REPEATABLE-READ
1 个赞
zhimadi
(Zhimadi)
2023 年6 月 30 日 10:32
15
REPEATABLE-READ
TiDB版本:v5.4.2
稍等我按你的这个脚本测试下贴个图
zhanggame1
(Ti D Ber G I13ecx U)
2023 年7 月 2 日 01:40
17
测试有结果了吗,我测了下7.1版本 for upate拿到的是最新值,不加for update就是旧值
zhimadi
(Zhimadi)
2023 年7 月 4 日 02:37
19
TiDB版本:v5.4.2
隔离级别:REPEATABLE-READ
B事务会阻塞,直到A事务提交拿提交后的数据。
zhimadi
(Zhimadi)
2023 年7 月 4 日 02:44
20
请问下,如果A事务有t1、t2表;B事务有t1、t2表。也是在刚才的场景下,对t1表加for update,更新t1和t2表。都B事务拿t2表是改动前还是后的数据?
xiexin
(荒岛)
2023 年7 月 6 日 09:56
21
那符合预期的呀,for update就是当前读,是会拿到最新的数据
前面你的问题是,事务1更新后,事务2for update查询到的是旧数据,那么这个问题就不存在了