关于在业务中 MYSQL 事务查询的一个疑惑

164 天前
 leejinhong

我有一个疑问,在实际业务中,当我们使用 MySQL 进行查询时,某一瞬间得到的值在下一瞬间可能会发生变化。这是否意味着在某一瞬间拿到的值不够可靠?

举个例子,在仓库库存管理中,如果在查询时库存是 30 ,但在查询完成后,其他业务操作改变了库存,导致库存变为 25 。然而,业务处理时依旧基于查询时的库存 30 进行操作,这样就会导致记录流水的值出现误差。

目前我能想到的解决办法是:

使用乐观锁,通过在记录中添加版本号或时间戳字段,在更新数据时进行校验,确保数据的一致性。 使用悲观锁,在查询时锁定数据行,直到事务结束,防止其他事务修改数据。 除此之外,还有其他方式可以解决这个问题吗?例如,在确保数据一致性和处理准确性的前提下,有没有更高效或更适合实际业务场景的方法?

2320 次点击
所在节点    MySQL
32 条回复
louettagfh
159 天前
举个例子,在仓库库存管理中,如果在查询时库存是 30 ,但在查询完成后,其他业务操作改变了库存,导致库存变为 25 。然而,业务处理时依旧基于查询时的库存 30 进行操作,这样就会导致记录流水的值出现误差。

你这个例子就不可能在 MySQL 中发生. 一个事务不结束, 其他无法事务修改这个 record.
leejinhong
159 天前
@louettagfh MYSQL 的隔离级别除非是串行化或者是你在查询的时候加上锁,不的话正常情况其他的事务都可以改当前的这条记录
louettagfh
158 天前
@leejinhong 你自己试一下呢? 看看能不能两个未 commit 的事务改同一个 record?
leejinhong
158 天前
@louettagfh #23 一个事务查询出来是 30 ,进行业务操作先不 commit ,另外一个事务直接变更 25 进行 commit ,是可以的。实际模拟很简单:A 脚本开启一个事务,进行查询那条记录记录为 30 ,然后 sleep 5 秒钟,这个时候开启另外一个脚本 B 里面更新那条记录,更新为 25 ,然后进行 commit ,这个时候脚本 A 里面查询 30 这个库存它就是错误的
louettagfh
158 天前
@leejinhong 你直接使用隔离级别 RR 不就行了
leejinhong
158 天前
@louettagfh #25 RR 隔离级别不就是可重复读? A 脚本在这个事务读取的就是开启事务时候的快照,这个时候的库存不就永远都是 30 吗?
louettagfh
158 天前
@leejinhong 使用 RR , 你的第二个事务不就改不了么, 这不就是你要的效果吗, 否则你又要别的事务可以改, 你又要第一个事务始终读取正确的值, 这不是数据库能保证的.
asmile1993
156 天前
@leejinhong 如果只是简单的 select ,在 RR 隔离级别下看到的的确是事务开始时的值,但当对记录进行修改操作时,用的是当前读—读最新的已提交记录,而不是一开始 select 得到的结果,想要了解更深的话,搜索下快照读和当前读。
leejinhong
156 天前
@asmile1993 你当前都最新提交的记录(这里的最新是相对来说的最新),如果你读到最新之后又有人修改了该条记录,它就不是最新的记录了
asmile1993
153 天前
@leejinhong 你为什么要以 select 出来的结果来做变更呢?上面已经有人提过了,你先用 select 查出来数据,判断是否能变更,如果不能,直接返回;如果能,那么就以 update t set value = value - 变化量 where ...,这样不就是当前读了吗?读的就是最新的数据啊,然后根据更新的行数来判断是否更新成功,0 则表示没有满足条件的记录,非 0 表示更新成功。
leejinhong
153 天前
@asmile1993 #30 首先:这个帖子主题的本质是想要了解有没有更好更优先非入侵业务的方案可供选择。 其次你以上说的这个 update t set value = value - 变化量 where ...这个是没问题的,但是有些业务是需要插入变动前、变动后的记录。
asmile1993
151 天前
@leejinhong 明白你的意思了,我记得流水表只记录差值,变更前后的值要靠当前值和差值构建出来。你要想记录,只能用悲观锁,变更前用 select ... for update/share 来读出最新值。

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

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

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

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

© 2021 V2EX