用 CTE 递归查询实现树形评论的分页展开
树形评论的分页是论坛和社区类产品里最容易被低估的一块。表面需求是"一页显示 20 条评论",实际难点在于:评论是嵌套的,一条根评论下面可能挂着十几层回复,你既不能让某一层的子回复被分页切口拦腰截断,也不能因为要算好层级导致每次翻页都全表扫描。很多项目最后退化成一次性把整棵树的评论全部查出来丢给前端拼,帖子一火,接口就是几百毫秒起步,内存里堆着上万行 JSON
FWDD.NET · 技术文档站
聚焦后端工程实践:语言教程、功能实现、面试题与运维脚本。每篇都从真实踩坑场景出发,给出可直接复用的代码与取舍依据。
树形评论的分页是论坛和社区类产品里最容易被低估的一块。表面需求是"一页显示 20 条评论",实际难点在于:评论是嵌套的,一条根评论下面可能挂着十几层回复,你既不能让某一层的子回复被分页切口拦腰截断,也不能因为要算好层级导致每次翻页都全表扫描。很多项目最后退化成一次性把整棵树的评论全部查出来丢给前端拼,帖子一火,接口就是几百毫秒起步,内存里堆着上万行 JSON
列表页一次性渲染 200 张商品图,首屏要下载十几 MB 的图片,用户滑动时白屏、闪烁、滚动位置乱跳,这是最典型的图片加载问题。把 loading="lazy" 加在 <img> 上只能解决「什么时候下载」,解决不了「下载之前这块地方占多高」。图片没有尺寸,浏览器在图片解码前把它当 0 高度处理,图片到达后页面被撑开,原本已经滚到第 80 条的用
订单超时关单、优惠券到期提醒、15 分钟未支付自动取消、消息重投退避——这类「到点才执行」的需求,用定时任务扫数据库是最容易想到的方案,但只要表一大、并发一高,就会出现扫全表慢、多个实例重复执行、任务取到一半进程挂掉导致丢失等问题。Redis 的 ZSET(sorted set)天生适合做这件事:score 存到期时间戳,member 存任务内容,按 sco
Go 标准库提供了 channel 来做协程间通信,但 channel 不支持「队列长度到达上限后单独统计丢弃次数」这类自定义策略;而在需要精细控制唤醒时机、需要复用同一把锁保护其他状态、或者需要实现「批量入队 / 批量出队」语义时,sync.Cond 是更合适的基础原语。本文从零实现一个泛型有界阻塞队列 BoundedQueue[T],包含 Put(满时阻
写 Rust 业务代码时,最容易卡住新人的不是所有权,也不是生命周期,而是函数返回 Result 之后,各种第三方库的 error 类型对不上:serde_json::Error 想变成自己的 AppError,std::io::Error 也想变成 AppError,偏偏 ? 一写就报 the trait bound `AppError: From<
在 TypeScript 项目里,把 unknown 或 any 收窄成具体类型是每天都要做的事。最常见的翻车现场是:接口返回的 JSON 被断言成 User,运行时字段缺失,页面白屏,控制台只留下一句 Cannot read properties of undefined (reading 'name')。类型守卫(type guard)就是解决这个问题的
很多人写 with 语句时只关心「打开、关闭」这一层,能跑通就不深究。可一旦业务里出现异常被悄悄吞掉、__exit__ 里抛出新的异常覆盖了原始异常、或者 GeneratorExit 让 @contextmanager 报出 RuntimeError: generator didn't stop after throw(),就会调上一两个小时。这篇文章把 w
crontab 用了二十年,但它有几个真问题:失败无感知、依赖无法表达、错过执行不补跑、日志散落。systemd timer 把这些都解决了。 crontab 的四个痛点 失败了没人知道 —— 除非自己重定向邮件,而邮件服务往往没配 无法表
systemd 能管大多数服务,但总有例外:容器里跑的业务进程、第三方不给 unit 文件的程序、需要按业务逻辑判断存活的场景。这时候一个轻量守护脚本比强行套 systemd 更实际。 探活:端口 vs 进程 只看进程活着不够——进程在但服