覆盖编码、调试、性能、异常、数据库、线上运维、工程化,都是日常写业务和做架构能用得上的实操经验。
一、编码与业务设计
参数先校验,业务后处理
不要相信上游传过来的任何参数。入参校验放在最前面,提前拦截非法数据,不要让脏数据进到业务逻辑、数据库。
不要靠数据库约束做业务校验,数据库约束用来兜底,不是业务第一道防线。
区分业务异常和系统异常
业务异常:参数错误、权限不足、状态不允许操作,返回明确业务码,不要打 ERROR 堆栈日志;
系统异常:数据库报错、调用第三方超时、空指针,打印完整堆栈,方便排查。
禁止直接把 Exception 堆栈抛给前端。
状态机管理业务状态,禁止硬编码判断
订单、流程审批这类多状态流转,写状态枚举 + 流转规则,不要到处写大量
if(status ==1 || status ==2),后续新增状态极易漏改。大方法拆分,单一职责
一个方法尽量不超过 80 行,一个方法只做一件事。业务逻辑、数据查询、组装返回、转换 DTO 分开,方便单元测试和阅读。
善用 DTO/BO/PO 分层,不要直接返回数据库 PO 对象
PO 对应数据库,BO 内部业务对象,DTO 对外输出。避免数据库字段变更直接影响接口返回,防止敏感字段泄露。
不要在循环里做数据库查询
N+1 查询是后端高频坑,循环内查库、循环调用 RPC,数据量上来直接雪崩,优先批量查询、join、批量 RPC。
二、数据库开发技巧
禁止 select *
只查需要的字段,减少网络传输、内存占用,避免表新增字段后意外带出大字段。
索引不是越多越好
索引提升查询,降低写入性能。联合索引遵循最左前缀;避免索引失效:函数运算、隐式类型转换、like % 前缀。
explain 定期看执行计划,不要凭感觉判断索引是否生效。
大表禁止轻易 alter table
生产大表 DDL 优先使用 Online DDL/pt‑online‑schema‑change,避开业务高峰,锁表直接导致服务不可用。
分页不要用 offset 大偏移
offset 100000 limit 10性能很差,改用游标分页(主键 id > 上一条 id)。事务粒度尽量小
事务里面不要放 RPC 调用、http 请求、复杂计算,尽量只放 DB 操作。事务过大锁持有时间变长,容易死锁、超时。
更新删除一定要带条件,执行前先 select 核对
生产执行 update/delete,先 select 验证 where 条件,防止误删全表;重要业务做逻辑删除,不物理删除数据。
时间字段统一用 datetime/timestamp,业务不要依赖数据库默认时间
业务代码显式赋值时间,避免数据库时区、版本差异带来时间错乱。
三、缓存 & 并发
缓存要处理缓存穿透、击穿、雪崩
穿透:查询不存在的数据,缓存 + 数据库都没数据 → 缓存空值、布隆过滤器
击穿:热点 key 过期,大量请求打数据库 → 互斥锁、永不过期
雪崩:大量 key 同时过期 → 过期时间加随机偏移
更新策略:优先数据库,再更新 / 删除缓存
先更新 DB,再删缓存;不要先更新缓存,数据库失败造成数据不一致。
不要用 Redis 做强一致性锁
Redis 分布式锁适合高并发场景的防重复,不能当做数据库级别的强事务锁;需要强一致性用数据库锁。
并发场景优先乐观锁
版本号
version实现乐观锁,避免大量悲观锁造成数据库排队。
四、日志、调试、排错
日志分级合理使用
info:关键业务节点(接收请求、完成处理)
warn:业务可预期异常,如重复提交
error:系统故障,必须带堆栈
禁止打印大量 debug 日志上线,会吃掉磁盘、拖慢性能;敏感信息密码、身份证不要打日志。
每个请求带上 traceId
全链路透传 traceId,日志全部打印,排查问题直接根据 id 检索整条调用链路。
接口耗时埋点
记录 DB、RPC、外部调用耗时,线上慢问题不用猜,直接看各阶段耗时。
本地复现不了,看日志而不是猜代码
线上优先看堆栈、参数、入参,不要盲目的改代码。
五、RPC / 第三方调用
所有外部调用必须设置超时时间
HTTP、RPC、MQ 消费,不设超时会线程池耗尽,服务卡死。
降级、熔断、重试
第三方不稳定时,配置熔断;重试要加退避策略,不要无限重试,防止雪崩。
重试一定要考虑接口是否幂等,非幂等接口不能随便重试。
幂等优先做
对外接口、消息消费,设计幂等逻辑,重复请求不会产生脏数据,用业务唯一标识做幂等键。
六、线上与工程化
配置全部放配置中心,不要硬编码
环境地址、密钥、开关、超时时间全部外部配置,改配置不用发布代码。区分开发、测试、生产配置。
线程池不要 new 出来,统一管理
自定义业务线程池,拒绝策略明确;禁止使用 Executors 默认线程池,容易 OOM。线程池命名,方便栈排查。
警惕内存泄漏点
静态集合无限存放对象、未关闭流、线程池线程持有大对象、大对象缓存不淘汰。
接口限流
对开放接口做限流,防止被刷垮;内部接口也要有保护,避免下游被打挂。
单元测试优先测边界
null、空集合、0、负数、最大最小值,大部分 bug 出现在边界条件,而不是正常流程。
发布习惯:小步迭代,灰度发布
不要一次性上大量改动;上线后观察监控、告警、错误日志,有问题快速回滚。
七、容易忽略的小细节
浮点数不要用来做金额计算,用 BigDecimal。
时间处理统一用 UTC 或者统一时区,避免时区混乱。
MQ 消息:消费一定要做好幂等,处理失败合理重试,避免消息丢失、重复消费。
接口返回不要返回 null,集合返回空集合
[],避免前端空指针。定期 Review 慢 SQL、大接口,不要等到出故障才优化。
本文原创作者:易君召,详见:https://www.yijunzhao.cn/authors/yijunzhao,转载请注明出处。
原文链接
欢迎访问 小易撩挨踢