什么时候可以将 mysql 默认隔离机制改为读已提交

2025 年 7 月 7 日
 byerer

新业务需要在事务中使用乐观锁,在 RR 下需要回滚重试整个事务,而 rc 只需要重试某一个更新,有必要改成 rc 吗,如何判断业务在满足什么条件下可以不依赖 rr ,是不是只要不依赖可重复读就行

4701 次点击
所在节点    MySQL
10 条回复
leopod1995
2025 年 7 月 7 日
RR 场景相当于在一个 transaction 中可以对一条读 sql 多次调用返回一致的结果,原理就是在一个 transaction 中生成了 snapshot 。一般不用 RC 的原因就是在一个事务中会重复调用同一条 sql 。

如果能保证一个 transaction 中没有重复 sql 的情况下,是可以替换的。
cubecube
2025 年 7 月 7 日
@leopod1995 根本不需要保证,随时都能改,oracle 默认是 rc ,用 oracle 的系统都好好的不是。rr 纯粹为了刷存在感。
Dorathea
2025 年 7 月 7 日
你都用乐观锁了, 那 RC 会比 RR 更合适吧, 毕竟你都觉得数据大概率不会冲突了
barnetime
2025 年 7 月 7 日
Georgedoe
2025 年 7 月 7 日
性能有瓶颈的时候吧 , 没瓶颈改了也没啥收益
857681664
2025 年 7 月 7 日
如果业务在一个事务中允许一个读出来的数据被其他事务更改,且不影响正常业务的逻辑就行。话说如果只是乐观锁,完全可以不用考虑 rr 还是 rc ,直接用 update 语句判断执行结果是不是更好。
iseki
2025 年 7 月 7 日
你不在乎多个请求查出的数据之间存在不一致的时候
iPisces77
2025 年 7 月 8 日
mysql 整体就是给 RR 设计的,其他数据库都是 RC,所以你改了也没啥影响
byerer
2025 年 7 月 8 日
@857681664 rr 情况下,在一个事务中,重试乐观锁的时候读不到最新数据呀,得先回滚事务
kanepan19
2025 年 8 月 26 日
@byerer

// @Transactional(rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED)
public void addBalanceByVersion(Long id, BigDecimal amount) {
//乐观锁 没有 for update
long systemTime = System.currentTimeMillis();
boolean flag = false;
while (System.currentTimeMillis() - systemTime < waitTime) {
flag = updateBalanceCheckVersion(id, amount);
if (flag) {
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (!flag) {
throw new BizException("加款超时,稍后再试");
}

}

要么不用事务,要么就加上 isolation = Isolation.READ_COMMITTED
都用事务了 老老实实的 select for update 或者 update xx set balance = balance - amount . 如果要记录流水还是 行锁。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1143515

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX