ARTS 0809: 反转链表、Shopify 如何用 MySQL 解决超卖与 AI 时代程序员的价值

每周完成一个 ARTS: 至少做一个 leetcode 的算法题、阅读并点评至少一篇英文技术文章、学习至少一个技术技巧、分享一篇有观点和思考的技术文章。(也就是 Algorithm、Review、Tips、Share 简称 ARTS)

Algorithm

这周是简单难度,反转链表 https://leetcode.cn/problems/reverse-linked-list/?envType=study-plan-v2&envId=selected-coding-interview

我也记录一下自己的两个错误的思路:

需要反转的链表:1 -> 2 -> 3 -> 4 -> 5

1)如果两两互换的话

1 -> 2 -> 3 -> 4 -> 5 把 2 插到最前 → 2 -> 1 -> 3 -> 4 -> 5 把 3 插到最前 → 3 -> 2 -> 1 -> 4 -> 5 把 4 插到最前 → 4 -> 3 -> 2 -> 1 -> 5 把 5 插到最前 → 5 -> 4 -> 3 -> 2 -> 1

这个思路和正确的思路其实是有点类似了,但是她需要把最后的结果和来源写到一起,非常乱

2)如果是首尾互换的逻辑呢,比如下面的例子:

text
复制代码
初始 1 -> 2 -> 3 -> 4 -> 5 ↑ ↑ 左 右 第 1 步:换 1 和 5 5 -> 2 -> 3 -> 4 -> 1 ↑ ↑ 左 右 第 2 步:换 2 和 4 5 -> 4 -> 3 -> 2 -> 1 ↑ 左右相遇(或交叉) 完成 5 -> 4 -> 3 -> 2 -> 1

如果这样写的话,那么需要前后两个不同的指针,而且这个 next 的逻辑比较麻烦

「正确」的思路:

1 -> 2 -> 3 把你这段代码逐步画开:

1、初始

text
复制代码
pre = null cur = 1 null 1 -> 2 -> 3 ↑ ↑ pre cur

2、第 1 轮

text
复制代码
① next = cur.next null 1 -> 2 -> 3 ↑ ↑ ↑ pre cur next ② cur.next = pre null <- 1 2 -> 3 ↑ ↑ ↑ pre cur next ③ pre = cur; cur = next null <- 1 2 -> 3 ↑ ↑ pre cur

3、第 2 轮

text
复制代码
① next = cur.next null <- 1 2 -> 3 ↑ ↑ ↑ pre cur next ② cur.next = pre null <- 1 <- 2 3 ↑ ↑ ↑ pre cur next ③ pre = cur; cur = next null <- 1 <- 2 3 ↑ ↑ pre cur

4、第 3 轮

text
复制代码
① next = cur.next null <- 1 <- 2 3 -> null ↑ ↑ ↑ pre cur next ② cur.next = pre null <- 1 <- 2 <- 3 null ↑ ↑ ↑ pre cur next ③ pre = cur; cur = next null <- 1 <- 2 <- 3 null ↑ ↑ pre cur

此时 cur == null,循环结束,return pre → 新头是 3

text
复制代码
3 -> 2 -> 1
java
复制代码
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public ListNode reverseList(ListNode head) { ListNode pre = null; ListNode cur = head; while (cur != null) { ListNode next = cur.next; cur.next = pre; pre = cur; cur = next; } return pre; } }

Review

文章是这一篇,关于 Shopify 单纯使用 MySQL 解决超卖的问题,原文链接: https://shopify.engineering/scaling-inventory-reservations

防止超卖一般需要两个操作:

  • Reserve(预留):支付开始时,把商品标记为已预留(短时占用,比如几分钟)。
  • Claim(核销):支付成功后,从库存 MySQL 扣减数量。

预留商品不能太久,要不然影响销量;支付成功核销不能太迟,否则客服有的忙了

Shopify 系统之前的做法是:

1、把预留操作再 Redis 里面进行,每一个商品一个 key ,如果触发预留操作就是用 DECR,核销操作就是 INCR。

2、核销完成之后就需要更新 MySQL

问题:

看起来很完美,Redis 能扛住并发,MySQL 也不会被直接打爆。但是真的这么完美吗?其实我们想一下,维护一套 Redis 集群当然这不是最大的问题,最大的问题就是不能把这两步合成一个原子操作,可能会出现超卖或者少卖问题。那么有没有更好的解决方案?

有没有其他的方案,有的稳重中提到了使用 MySQL8.0 的 SKIP LOCKED (下面有这个的介绍)新特性进行解决,怎么解决?

很巧妙,他把库存不单独存储再一个行里面,而是有多少库存插入多少行记录,在加持上这个 SKIP LOCKED 特性,不仅保持的 ACID 而且还减少 Redis 维护成本,非常舒服~

虽然之前没有办法解决的问题,但是现在由于 MySQL 的更新,解决起来也更简单,时代真的是会变化的。


面试鸭上面也有关于 SKIP LOCKED 的介绍 https://www.mianshiya.com/question/1780933295505174530#heading-5

image-20260809204107781

Tips

1、Github Action 打包 docker image 真的好用,现在 AI 时代让 AI 写一个 yml ,之后用 Github Desktop push 到远程上面也非常方便。我本地 build 需要花了很久才还没好,我直接暂停。

2、Cursor 会读取 Claude 的 skills 会占用很多宝贵的 context ,建议检查一下

3、之前看社区说 Opus5 效果不太好,有人说可以用 Opus4.8 plan + Opus5 执行

Share

大佬的观点 https://blog.senko.net/code-was-never-the-hard-part-is-an-insult-to-all-programmers

作者反驳「写代码很容易,难的是想清楚做什么」:写代码本身就是硬手艺——高薪、面试、经典著作、天才程序员和遍地 bug 都说明这一点;反过来,「定需求更难」也经不起推敲,否则 PM、调研、客成早该是公司明星。真正重要的是两者都要:既懂系统怎么建,也懂为什么建。面对 AI 变革别靠自我安慰,要好奇又批判地适应;变的是工具与角色,不变的是复杂度、维护、用户说不清需求。别把理解、判断和品味外包给 AI。

PS 我最近还看到开发 FFmpeg 和 VLC 的 Podcast(虽然没看完😂) ,大佬是真的牛

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
leikooo
作者分享
ARTS 0815: 分隔链表、大删除是加活不是减负与协议栈如何一层层拆信封
3
DeepSeek Harness 缓存命中率太惊人了,有时候竟然能到 99%,看鱼皮哥的视频竟然还出现过 100% 😱 https://www.bilibili.com/video/BV1VkgK6NEZS
7
译文:《SwiftUI 七年:平庸的故事》 SwiftUI 在 2019 年高调发布,本应成为苹果全平台成熟、可量产的 UI 未来。七年过去,到了 2026 年,它仍像一场永不结束的 beta:布局难预期、性能不稳、数据流混乱,还几乎没有可靠的向后兼容,开发者被迫写一堆 shim 和 workaround。 作者用苹果官方教程(甚至是有问题的)以及与 UIKit 的对比说明:SwiftUI 用“看起来方便”换掉了精确的工程控制。更深一层,他认为这反映了苹果从 Cocoa、Aqua、Auto Layout 那种不妥协的工艺,转向“够用就行”的企业文化。 SwiftUI 为何存在 苹果并非单纯想提供更好工具,而是不得不应对竞争:React、React Native、Flutter 让“一套代码多端跑”变得诱人;Mac 上原生应用又日渐被网页和 Electron 吃掉。SwiftUI 要同时拴住原生生态、并降低移植到 Mac 的成本。卖点是:响应式数据流、声明式布局、跨平台复用。 数据流 “单一数据源”听起来很美,实际却是 @State、@Binding、ObservedObject,再到 Observation / @Observable 的不断换代。你很难确定视图会更新几次、为何更新;它该忽略的变化会反应,该关心的变化又可能忽略 - - 像个黑盒。 布局系统 基于尺寸协商的布局在 Keynote 里很合理,做浮动视图、自定义侧边栏时却极度不稳定。官方教程里一个很普通的侧边栏,多年仍有问题。布局脆弱到最后往往只能上 GeometryReader - - 一旦用了,声明式优势就没了,还要手算坐标,而且下一版布局规则一变,数学还得重写。 API 稳定与功能对等 代码里满是 if #available。滚动收起键盘要到 iOS 16;工具栏定制很晚才来;网络图片 AsyncImage 要到 iOS 15,缓存相关 API 到 2026 年 7 月仍在 beta。旧 API 常被换掉(如 NavigationView → NavigationStack),开发者要维护多套实现,等于替苹果做 QA。对比 Android 的 Jetpack Compose 可作为依赖打包回退到旧设备,SwiftUI 做不到“写最新 API、稳定回退”。 性能 在真实对比里,即便做了后台解码等优化,SwiftUI 图片网格滚动仍明显不如 UIKit。若展示一堆 JPEG 都得靠顶级芯片撑,架构本身就有问题。 跨平台神话 苹果说的是“学一次、到处用”,不是“写一次、到处跑”。iOS 上学到的布局很少直接适用 Mac;同一套 view 跨平台实现也不一致。结果常变成:学一次、再学一次、某处能用、处处要调。 哲学转向 最大的问题是“够用就行”:覆盖 90% 用例就算成功,用 velocity 掩盖质量下降。作者列举系统与一线应用中的各种瑕疵,认为这不是偶然,而是苹果主动降低质量门槛 - - 所以即使过了七年,他仍不信任 SwiftUI。 结论 对构建稳定、高性能、可维护系统真正重要的部分,SwiftUI 几乎都有问题。它不是“极差”,而是平庸 - - 用假便利换真精度,要么你花时间给框架打补丁,要么把半成品发出去。作者更宁愿继续用“遗留”的 UIKit / AppKit。 最后小总结: 最让人不能接受的不是“SwiftUI 还有 bug”,而是它把“看起来很快”当成了工程上的完成态。声明式、预览、跨平台,每一项都在秀高级感,可真正写进业务后,你面对的是难预测的重绘、脆弱的布局、层层 #available,以及把兼容和排错外包给业务方的现实。七年够长了,若还靠“框架还年轻”解释,那更像是对标准的侮辱。技术选型从来不只是语法偏好,而是你选的是可预期性、可维护成本,以及对用户体验的态度。平庸的“成功”往往比明显失败更危险 ,你说它能上线、能 demo、能交差,但是却在细节里一点点磨损信任。工具可以换代,但对质量的要求不该跟着一起降级。
4
ARTS 0802: 合并有序链表、AI 时代的技术断层与 TCP 200ms 延迟之谜
5
Spring 团队开发者布道师 Josh Long,从 2011 年起每周二坚持写 This Week in Spring https://spring.io/authors/joshlong,大概 15 年半从未间断,到现在大概写了 800 期以上😱 大佬在采访里他说,写博客不是额外负担,而是逼自己整理每周所学的「强制机制」——反正本来就会刷社区动态,写出来既方便自己,也帮到别人。更重要的是 Spring 一直在变:微服务、AI……永远有新东西可聊,停一周就容易掉队。一旦养成习惯,坚持往往比重新开始更容易。 这种级别的大佬都还在用周更逼自己不掉队,我更没理由再拖了。还有之前左耳朵耗子大佬说的 ARTS 打卡,我老实说只撑了两周,真的需要捡起来了,加油✊
10
下载 APP