侧边栏壁纸
博主头像
why

一个主要敲代码,经常怼文章,偶尔拍视频的成都人。

  • 累计撰写 197 篇文章
  • 累计创建 11 个标签
  • 累计收到 101 条评论

事务-我就辣鸡怎么了?

why
why
2021-09-03 / 0 评论 / 0 点赞 / 586 阅读 / 1,729 字
温馨提示:
关注公众号why技术,第一时间接收最新文章。

你好呀,我是why。

是这样的,我周一的时候不是发了《仔细思考之后,发现只需要赔6w》这篇文章吗。

好家伙,我以为这事写个上下集就算是大结局了。

没想到,还需要补一篇来说明一下。

首先,给大家说一声对不起,我错了。

那篇文章里面有一个基本的论点是错误的,就是这里:

是的,错在了天王老子这一句,脸打的啪啪的,老疼了。

现在,我重新描述一下天王老子这一句:

在 10 个库存,100 个并发的前提下,就算是王母娘娘来了,绝大部分情况下订单数都是 20 个,但绝不可能超过 20 个。

下面我解释一下什么情况下订单数会小于 20 个。

还是拿这个图片来说事:

首先,这个图片我是截取了一部分日志,根据日志画出来的图:

日志里面打印的 Thread-107 的库存是 2,于是我画到图中。

所以我上篇文章里面的推理过程是没有错的,换句话说,那篇文章解释了为什么大多数的情况下订单跑出来都是 20 个,即日志为什么是这样打印的。

虽然我自己跑了不下 100 次,每次都是稳定 20 个。

但是日志一直都这样打,就能推理出订单数一定是 20 个吗?

不能。

是的,不能啊。打完脸之后,我给你分析一下。

问题就出在 Thread-107 查询出库存为 2 这一步,我把情况最简化,重新打上时间标记,基于这个图去说:

首先,T2、T3 时刻一定是晚于 T1 时刻,T2、T3 时刻是推导不出先后关系的,这个不再多说。

那么假设,最开始的情况下库存就是 2 个。

T2 时刻事务还没来得及提交,就执行到 T3 时刻,那么 T3 时刻查询到的库存就为 2。

如果 T2 时刻事务已经提交完成,然后执行到了 T3 时刻,那么 T3 时刻查询到的库存就为 1。

现在,假设 T3 时刻查询到的库存是 1,那么同理,下面的 T4 时刻是不是有可能为 1,也可能为 0:

如果查出来为 0,那么就和前面的文章里面的这个结论冲突:

因为前面文章的这个结论是基于程序的运行日志得出来的。

现在理论有了,那么我怎么模拟一下订单数少于 20 个的情况呢?

想要模拟出这个情况,根据我们前面的分析只需要保证 T3 查询库存的操作晚于 T2 提交事务的操作。

那么自然而然的就想到了在查询库存之前加入睡眠时间:

但是,你会发现这样加,订单每次都是 10 个了呀,这个情况没啥好分析的,就类似于每隔一秒发一个下单请求。锁早就释放了,事务也早就提交了。

所以,我改成了这样:

意思就是如果抢到锁的线程名称包含 1,就休眠一下。

比如模拟程序进入了 GC,发生了 stop the world。

再次执行程序,日志就变成了这样:

可以看到,没有出现连续两个库存为 5,总订单数也变成了 19 个。

验证完成。

甚至,我可以扩大线程名称的命中范围,比如这样,就只有 12 单了:

另外,在提一下另外一个问题。

有的同学用分布式锁去做了验证,发现并没有出现超买的情况。

可以在释放锁之后加上一个睡眠时间试一试。

这样做的目的是延迟事务提交的时间,以保证下一个抢到锁的线程读到的是未提交之前的库存。

好了,上面说了这么多,就是纠正一下之前文章中说的过于绝对的地方,确实是我写的时候被绕进去了。

我也狡辩一下。

你都不知道,我周末写那篇文章的时候晚上洗澡都在想着去证明一个点:

订单数会不会出现超过 20 的情况?

害,没想到它在 10 到 20 之间埋伏了我一手,防不胜防啊。

我个人是觉得分析小于 20 单的情况比较简单,逻辑也很清楚,还是分析等于 20 单的情况有意思。

另外,写到这里我想起之前知乎看到的一个故事,和大家分享一下。

通过我自己的验证,我跑了上百次的实验,每次都是 20 单。

因为相对于查询语句,事务提交是一个比较重的过程。所以,20 单应该是一个绝大部分同学都会遇到的情况。

但是真的就有一个同学他跑出了 19 单的情况,然后他来问我为什么。

原因前面我解释了就不再赘述了。

那假设,如果有人连续 100 次、1000 次甚至上千万次,都跑出了小于 20 的这样的小概率事件。

那么,你的程序的环境的某个环节一定出了大问题。

小概率事件的发生,说明很可能出了大问题。

下面这个知乎回答,分享给你:

最后说一句(求关注)

好了,看到了这里了,关注一下我的公众号[why技术]吧,文章写好后第一时间会先发布在公众号里面。

写文章很累的,需要一点正反馈。你的关注,就是强有力的正反馈!

才疏学浅,难免会有纰漏,如果你发现了错误的地方,还请你留言给我指出来,我对其加以修改。

抱拳了,铁子!

0

评论区