库存扣减,余额扣减,应该使用乐观锁的方式吗?

2020-04-29 09:56:54 +08:00
 watzds
和这种直接扣减的方式相比,有什么好处呢?
UPDATE stock SET amount = amount - $diff WHERE id=$id AND amount>$diff;

有些文章说是乐观锁方式可以在重试时保证幂等性,不过什么时候会重试呢
1. 超时?如果重试又失败,那怎么判断是之前已经成功还是后来竞争失败呢?怎么返回结果给上层呢
2. 如果是获取版本号一起被重试,那也没什么幂等性了

总觉得没说服力,五十步笑百步的感觉,想要实现幂等性,最终还是需要其他辅助手段。
这种方式是有什么其他原因吗,比如性能,正确性?

说是幂等性优点的(架构师之路): https://mp.weixin.qq.com/s/xXju0y64KKUiD06QE0LoeA

还有《企业 IT 架构转型之道》这本书里,是将乐观锁扣减方式和 select for update 相比较,没提什么 where 限制扣减,幂等性之类


大家是用什么方式,这种乐观锁覆盖实现扣减到底有什么好处呢?
6538 次点击
所在节点    程序员
27 条回复
bowie
2020-04-29 16:08:11 +08:00
你这种写法都不是什么锁,只是能够保证不会被扣负,所以也不能和 select for update 比较吧,这样写也解决不了并发问题呀
watzds
2020-04-29 16:38:05 +08:00
@bowie #21 是的,只保证不会被扣负,不过什么余额、库存业务场景,不被扣负还不够呢?这个经验不多,能举些实际例子吗
只扣个余额, 要是用 select for update 或者乐观锁,是否 overkill
watzds
2020-04-29 17:54:47 +08:00
@lhx2008 #17
嗯,查了一下 commit 成功,但是返回给客户端失败的情况,应该没有标准处理,不过也极少发生,oracle 倒是有一些机制 Transaction Guard
https://dba.stackexchange.com/questions/215579/what-happens-if-the-database-nodes-network-fails-just-after-commit-and-before-r?newreg=e21a89d0f6e3489b85a0a4e99ba08c6b
xmh51
2020-04-30 09:56:44 +08:00
@watzds 常见的需求 扣款同时添加一个流水记录
watzds
2020-04-30 12:20:50 +08:00
@xmh51 嗯,如果除了扣除数据,还要记录扣款前后数量的话
bowie
2020-05-06 18:02:48 +08:00
@watzds 你这个单机是问题不大,如果是正常项目里面就不能这么玩,比如多线程情况下
线程 1:
库存:10,扣减 10,剩余库存:0
线程 2:
库存:10,扣减 5,剩余库存:5
这样结果就不对了
如果并发小的话这种扣减数据库层用乐观锁+保证事务一般就可以了,如果并发很大的话业务层还要用队列和做分布式锁,具体的还是要根据业务场景和系统架构设计来灵活处理
watzds
2020-05-06 18:43:08 +08:00
@bowie 这个语句当然不只是单机,分布式都能正确,update 是当前读都会加锁的啊

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

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

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

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

© 2021 V2EX