模块六 · AI 协作与表达
AI 协作与代码评审:把后端风险挡在合并之前
后端 AI 代码的错误代价不对称——生成一分钟,出错赔数据。这一节给出接口契约先行、事务与并发审查、SQL 与幂等的检查清单。
读完这一节,你能做到
- 说清后端场景里 AI 协作的风险为什么和前端不同。
- 用带版本与中间件现状的上下文,一次要出能落地的实现。
- 按「接口契约 → 单测 → 实现 → 事务并发审查」的顺序推进。
- 用五个后端检查点审出事务失效、线程池耗尽、N+1、重复扣款。
- 用编译、单测、集成测试与 SQL 日志证明改动没有变坏。
一、风险不对称
前端写错,用户看到白屏;后端写错,可能是一批数据错、一笔钱多扣、一个事务没回滚。AI 生成一段能通过编译的代码只要几十秒,而它引发的事故排查常常以小时计。
| 它很擅长 | 它经常错 |
|---|---|
| CRUD 骨架、DTO 与校验注解 | 事务边界(自调用、事务里做 RPC) |
| 常见设计模式与工具类 | 并发安全(共享可变状态、线程池配置) |
| 单元测试骨架 | 查询性能(N+1、索引失效) |
| 配置项与脚手架 | 幂等与重试(重复提交、重复消费) |
判断原则:后端的"能跑"是最低标准。 通过编译、跑通一次请求,只能说明语法与主流程对;真正决定成败的是事务、并发、性能与幂等。
二、上下文:版本与事务边界必写
后端上下文比前端多两项硬约束:框架版本和事务管理器。
- 目标:哪个接口、什么业务动作、验收看什么。
- 现状:JDK 与 Spring Boot 版本、ORM 选型、事务管理器配置、现有 DTO 与异常体系、分库分表与否。
- 约束:不新增依赖、必须走现有
Result包装、事务只包 DB 操作、不许在事务里发 MQ。 - 验收:行为级——重复提交只生效一次、下游超时能补偿、单次请求 SQL 条数上限。
反例:帮我写一个下单接口。
正例:目标:下单接口,扣库存 + 建订单 + 发履约消息。
现状:JDK 17 / Spring Boot 3.2,MyBatis-Plus,事务管理器是 DataSourceTransactionManager,
异常统一走 BizException,消息用 RocketMQ,已有 outbox 表。
约束:不新增依赖;事务内只做 DB;消息走 outbox 异步投递;不许用 @Transactional 包 RPC。
验收:并发下库存不超卖;同一幂等键重复请求只生成一单;单次请求 SQL ≤ 6 条。
第二段的价值不在"写得长",而在它把事务边界和幂等键这两件最容易出事的事提前钉死了。
三、拆任务:契约先行,实现在后
后端推荐的顺序与前端不同——接口契约先定,单测跟着契约走:
① 接口契约(入参/出参/异常码/幂等键)
② 失败路径的单测(先红)
③ 实现(事务、DAO、消息)
④ 事务与并发审查(单独一轮,只审不写)
第一步定契约,AI 后面写的实现就被约束住了;第二步先写失败路径的测试,能逼出"异常怎么处理"这一层它最常偷懒的地方;第四步单独审事务与并发,避免和功能改动混在同一个 diff 里。
粒度标准:一次 diff 能在 10 分钟内逐行看完。 一个带事务、消息、缓存的接口,通常要拆成 2-3 轮。
四、五个后端检查点
第一点:事务边界
@Transactional是否发生在同类自调用上?那样代理不生效,事务根本没开。- 事务里是否做了 HTTP 调用、消息发送、文件上传?长事务会拖死连接池。
- 异常是否被吞掉?捕获后不抛,事务就不会回滚。
rollbackFor的默认值只回滚运行时异常,受检异常要显式声明。
第二点:并发与线程池
- 线程池是否用了无界队列?那等于放弃背压,任务堆到 OOM。
- 共享可变状态有没有保护?
SimpleDateFormat、非线程安全集合是最常见的产物。 ThreadLocal用完remove()了吗?线程池复用会串数据。CompletableFuture用的是默认线程池吗?IO 任务和计算任务混在一起会互相饿死。
第三点:SQL 与索引
- 循环里逐条查(N+1)?批量查询或
IN一次拿回来。 - 索引最左前缀被破坏了吗?函数、隐式类型转换、
like '%x'都会失效。 - 分页
count是不是每条都跑?大表上这是隐形炸弹。
第四点:幂等与重试
- 幂等键存在哪、多久过期?没有幂等键的重试就是重复下单。
- 消息消费端做了去重吗?MQ 至少一次投递意味着一定会重复。
- 重试有没有退避?无间隔重试会把下游打挂。
第五点:资源与可观测性
- 流、连接、锁是否在
finally或 try-with-resources 里释放。 - 关键路径有日志与耗时打点吗?出问题时能不能定位到是哪一段慢。
- 日志里有没有手机号、身份证、token?后端的日志合规风险比前端高。
五、验证:三道闸
- 静态闸:
mvn -q compile/gradle compileJava+ 静态检查。拦掉类型与 API 误用。 - 行为闸:单测覆盖失败路径(异常、超时、重复提交),集成测试跑真实数据库与事务。
- 数据闸:打开 SQL 日志数一数条数;并发测试跑一次库存扣减;看连接池与线程池指标。
第三闸是后端特有的一闸:逻辑正确但 SQL 爆炸、或并发下超卖,都会在前两闸全绿的情况下发生。
六、算例:一个下单接口的两种做法
任务:下单(扣库存 + 建单 + 发消息),要求幂等。时长示意。
做法 A:一次要完
| 项 | 耗时 |
|---|---|
| 写提示词、等生成 | 3 分钟 |
| review 260 行 | 25 分钟 |
| 发现事务里发了 MQ,改 outbox | 返工 40 分钟 |
| 压测发现超卖,加乐观锁 | 返工 30 分钟 |
| 合计 | 98 分钟 |
做法 B:拆四轮
| 轮次 | 交给 AI 的 | 自己做的 | 耗时 |
|---|---|---|---|
| ① 契约 | DTO 与异常码 | 定幂等键与错误语义 | 10 分钟 |
| ② 失败路径测试 | 用例骨架 | 补重复提交、超时断言 | 15 分钟 |
| ③ 实现 | DAO 与事务骨架 | 加乐观锁、改 outbox | 20 分钟 |
| ④ 事务并发审查 | 无(只审) | 逐条过五个检查点 | 10 分钟 |
| 合计 | 55 分钟 |
净收益 = 生成节省的时间 − (审查 + 返工 + 事故成本)
后端还有一项容易被忽略的成本:事故成本不是线性的。 超卖 3 件可能只是赔钱,重复扣款上了热搜就是另一个量级。
七、常见坑
- 以为编译通过就是对的。 事务、并发、索引都不在编译器的检查范围内。
- 让 AI 决定事务边界。 它默认把整个方法包进事务,包括 RPC。
- 不看 SQL 日志。 N+1 在开发数据量下完全无感,上线就炸。
- 幂等只在"想法"里。 没有落地成幂等键,就等于没有。
- 把生产数据贴进提示词。 订单号、用户信息、内部表结构都属于敏感信息。
- 一次让它改十个文件。 后端改动的影响面比前端大,diff 越大越不敢合。
八、面试怎么讲
后端岗位问 AI,多半会追问"你怎么保证不出事故"。
怎么用:契约先行,先写失败路径的单测,再让它填实现,最后单独一轮审事务与并发
怎么验:编译 + 单测 + 集成测试,外加 SQL 条数与并发压测
踩过什么坑:它把 MQ 发送写在事务里,回滚后消息已经出去了;后来统一走 outbox
换来什么:一个接口从 98 分钟降到 55 分钟,返工集中在"幂等与事务"这类结构问题上
一句话加分项:"AI 能写对 happy path,事故基本都出在失败路径和并发上,所以我把审查预算全放在这两块。"
九、动手任务:自写 → AI 写 → 对比 → 取舍
四步不跳:① 自己写(限时,关掉补全)→ ② 让 AI 写同一题 → ③ 逐条比对 → ④ 说出保留谁的写法。
① 自己写
- 写一个幂等的下单接口:扣库存用乐观锁,消息走 outbox,重复提交只生成一单。
- 给这个接口写三条失败路径单测:库存不足、重复提交、下游超时。
② 让 AI 写同一题
把第 1 题交给 AI,补一句 Spring Boot 3.2 + JDK 17,事务内只做 DB,MQ 走 outbox,必须幂等。
③ 对比要盯的点
| 检查面 | 我的版本 | AI 版本 | 差异说明 |
|---|---|---|---|
| 事务边界 | |||
| 幂等键 | |||
| 并发扣减 | |||
| SQL 条数 |
④ 说取舍
- 它把消息发送放在事务里了吗?回滚之后消息会怎样?
- 它的幂等键存在哪、多久过期?
- 两个人同时下单同一件库存 1 的商品,它那版会超卖吗?
十、自测
- 后端 AI 协作的风险为什么和前端不对称?
- 上下文里哪两项是后端必写、前端可以不写的?
- 为什么推荐"契约先行 + 失败路径单测先行"?
- 五个后端检查点分别是什么?
@Transactional在什么情况下会静默失效?- 三道闸里的"数据闸"具体看什么?
参考答案要点:错误代价是数据与资金,且不可回滚;框架版本与事务管理器;契约约束实现、失败路径是 AI 最常偷懒处;事务边界、并发线程池、SQL 索引、幂等重试、资源可观测;同类自调用、异常被吞、受检异常未声明 rollbackFor;SQL 条数、并发压测、连接池与线程池指标。
配套题目
★ 越多越该先背;点题目可看完整答案与深入版。
- ★★★★★ AI 生成的 Java 接口代码,你会重点审什么?
- ★★★★☆ 怎么给 AI 描述后端上下文,才能避免事务出错?
- ★★★★☆ AI 写的并发代码有哪些典型坑?
- ★★★★☆ AI 生成的 SQL 与 ORM 代码怎么验证性能?
- ★★★☆☆ AI 时代还需要背 JVM 与 Spring 源码吗?
- ★★★★☆ AI 能写完接口,为什么还强调幂等与失败路径?
提示:读完可以顺手做几道对应题目,检验是否真的理解