@Transactional 嵌套调用中 REQUIRES_NEW 与连接池耗尽的关系判定
面试里常听到这样一句结论:「REQUIRES_NEW 会挂起外层事务、占用两条数据库连接,嵌套一两层就把连接池打满了。」这句话一半对一半错。对的部分是 REQUIRES_NEW 确实会新开连接;错的部分是——真正导致连接池耗尽的往往不是"多占一条连接",而是外层事务卡在等锁或等结果,内层又拿不到连接,形成互相等待的僵局。本文用一个可复现的工程,把"占用两条连
面试里常听到这样一句结论:「REQUIRES_NEW 会挂起外层事务、占用两条数据库连接,嵌套一两层就把连接池打满了。」这句话一半对一半错。对的部分是 REQUIRES_NEW 确实会新开连接;错的部分是——真正导致连接池耗尽的往往不是"多占一条连接",而是外层事务卡在等锁或等结果,内层又拿不到连接,形成互相等待的僵局。本文用一个可复现的工程,把"占用两条连
这道题在面试里出现的频率很高,但真正能讲清楚的人不多。多数人背下来的答案是「fork 之后子进程和父进程共享物理页,页表项被标成只读,任何一方写入就触发缺页,内核复制一份新的物理页」。这段答案本身没错,可它只覆盖了从 fork 返回、到某一方第一次写入之间的那一小段。面试官一旦追问「exec 的时候这些页怎么办」「如果子进程还没写就 exec,父进程的页会不
面试里问 sync.Pool,多数人能背出「临时对象复用、减轻 GC 压力」,但真正能区分候选人的是细节:GC 到底怎么清空 Pool?清空之后马上 Put 进去的对象,会不会在下一轮 GC 又被清掉?为什么必须调用 runtime.GC() 两次才能观察到一个对象从 Pool 中彻底消失?Put 里的对象什么时候会被「私吞」而不是进入共享队列? 本文从 G
面试里只要提到 TypeScript 条件类型,面试官十有八九会追问一句:「为什么 T extends any ? T[] : never 传入联合类型后返回的是联合的数组,而不是数组的联合?」紧接着还会补一刀:「那如果传 never 呢?」这两个问题看着小,实际上分别打在了 distributive conditional types(分配式条件类型) 和
线上排查一个用户操作日志丢失的问题时,链路信息(traceId、userId)在 Controller 里明明已经写进了 InheritableThreadLocal,可一进业务代码里通过 @Async 或手动提交的线程池任务,日志里的 traceId 就全变成 null。很多人第一反应是"继承的 ThreadLocal 没生效",于是继续在工具类上加装饰、
单例(Singleton)是面试里被问烂的模式,但真正能区分候选人水平的,不是「你怎么写单例」,而是「你的单例在反射和序列化面前还剩几条命」。很多人在白板上写出 private static class Holder 版本,觉得既延迟加载又线程安全,已经是满分答案;面试官接着追问一句「我用反射把它构造两次,你怎么办」,回答就开始含糊了。这篇文章把两种常见的高
在 Go 面试里,只要聊到并发,select 几乎是必问项。而一旦候选人能说出 select 的语法,面试官往往会追一句:「那 select 里加 default 会发生什么?会不会空转?」再往下就是经典陷阱:「time.After 放在 for + select 里会不会漏定时器?」 这两问看着是语法细节,实际考的是三件事:对 select 调度语义的理解
面试里经常出现这样一道题:表上建了联合索引 (a, b, c),SQL 写成 WHERE b = 1 ORDER BY a,问能不能用上索引排序。很多人背过结论——「最左前缀原则」——但一旦列顺序和 WHERE 条件顺序不一致、或者 WHERE 里出现范围查询、或者 ORDER BY 的列顺序与索引顺序颠倒,就开始含糊。这篇文章把「排序失效」这件事拆到可判定
批量发起接口请求几乎是每个前端都会遇到的场景:页面初始化时要同时拉用户信息、权限列表、字典数据和消息未读数,导出报表时要按分片并发下载。多数人第一反应是 Promise.all,因为它写得最短。但真正上线后才会发现,Promise.all 的语义是「全有或全无」——任意一个请求 reject,整个结果就变成 reject,那些已经成功返回的数据被直接丢弃,页