数据库层面
数据描述 | 案例 | 备注信息 |
---|---|---|
禁止对大表在高峰期建索引 | - xxx_log(2000w+)对 xxx_log 表建索引,导致表锁超过2min,严重影响业务,所有新增日志被阻塞 | |
禁止对大表在高峰期进行类型变更 | - message_xxx (500w+)ALTER TABLE message_xxx MODIFY COLUMN error longtext NULL COMMENT '错误'影响消息发送,业务严重阻塞 |
// 其他线程获取连接超时Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: master - Connection is not available, request timed out after 30000ms. |
采用默认连接池 | 连接池过小,并发高时连接快速被打满,导致整个生产系统变慢 | 如HikariCP默认maxPoolSize=10 |
一个没有索引的UPDATE 或DELETE 语句(WHERE 条件无法命中索引),会对全表进行扫描和锁定,等效于一次锁表操作 |
UPDATE huge_table SET status = 1 WHERE create_time > '2023-01-01'; (如果create_time 无索引) |
|
未加索引的模糊查询引发全表扫描 | SELECT * FROM order_log WHERE mobile LIKE '138%'; | |
大批量数据删除或更新时未分批次操作(同上) | DELETE FROM operation_log WHERE create_time < '2022-01-01'; (无索引或即使有索引也可能产生巨大事务),单事务过大(删除5000w行) |
|
排序字段没有索引导致分页数据重复 | order by 字段, 字段没有索引,导致分页查询时出现数据重复情况。分页数据不稳定 |
避免高峰期变更,工具化安全改表
在高并发、大数据量场景下,数据库是系统的瓶颈点之一。尤其当单表数据量超过百万级(如500万+),任何DDL(数据定义语言)操作都可能引发锁表、主从延迟、连接池耗尽等严重问题
指标 | 风险阈值 |
---|---|
单表行数 | > 500万视为"大表" |
DDL执行时间 | > 30秒需评估影响 |
锁等待超时 | lock_wait_timeout > 60s 视为高危 |
代码层面
jdk8 注意事项
相关API | 具体描述 |
---|---|
Collections.sort(list) | list 含 null 元素 → NPE,推荐使用 Comparator.nullsFirst() |
Collectors.toMap | 重复值 Duplicate key 错误.....value 的 function 计算结果 null 引发 NPE |
parallelStream 并行流 | ThreadLocal#get() 为 null可能导致非线程安全类出现并发异常 |
stream#sort 排序 | 排序字段为 null,引发 NPE,多字段排序时此类问题尤为常见 |
java.util.Optional#get/of | of 入参为 null,引发 NPE; get() 返回值为 null 时可能引发异常.... |
常见编码
相关API | 具体描述 |
---|---|
资源未关闭导致内存泄漏或文件句柄耗尽 | // 使用 try-with-resources(推荐)。 try (FileInputStream fis = new FileInputStream("file.txt"); BufferedReader br = new BufferedReader(new InputStreamReader(fis))) { // 自动关闭 } catch (IOException e) { e.printStackTrace(); } |
吞掉异常 | try {riskyOperation();} catch (Exception e) {// 吞掉异常,导致问题被隐藏,极难排查} |
ThreadLocal 需要 remove | try {UserContext.setUser(user);// 处理业务} finally {UserContext.userHolder.remove(); // 必须 remove!}ThreadLocalMap 使用 WeakReference 作为 key,但 value 是强引用。key 被回收后变成 null ,但 value 仍存在 → "弱引用 key + 强引用 value" 导致内存泄漏 |
Arrays.asList() 返回的 List 不能修改 | List list = Arrays.asList("a", "b", "c");list.add("d"); // UnsupportedOperationExceptionlist.remove(0); // 同样异常Arrays.asList() 返回的是 Arrays 的内部类 ArrayList (注意不是 java.util.ArrayList ),它不支持增删,只支持 set() |
BigDecimal 的正确使用 | 用于金融计算时,必须使用 BigDecimal ,且避免使用 double 构造函数BigDecimal price = new BigDecimal(0.58); // 可能出现精度问题BigDecimal price = new BigDecimal("0.58"); // 使用字符串构造 |
建议方法不要返回 null 值 | 使用 |
NoSuchMethodError 不属于 Exception,而是 Error; 在一些反射时候,捕获catch 要留意 | 属于 Error 类型,注意 catch Throwable |
空值检查与防御性编程
相关API | 描述 |
---|---|
使用 Optional / Object.isNull | 做好空值控制和防御性编程 |
边界值
相关API | 描述 |
---|---|
while(true)/for(;;) | - 一定要注意异常的情况,最终导致不能退出 |
多线程
相关API | 描述 |
---|---|
parallelStream | 使用线程不安全的API,比如 ArrayList、ThreadLocal#get等 |
优雅关闭 | 对于重要任务,未进行优雅关闭 |
CompletableFuture | 设置最大等待时间处理好异常(exceptionally方法来处理异常情况) |
CountDownLatch | 保证 countDown 一定会被执行(注意异常,放在 finally 方法中)设置最大等待时间防止其中一个操作阻塞或者出现异常,导致整个操作链死锁 |
事务失效场景
- 在非public方法上用@Transactional不会报错,但也不会生效。就跟没写一样
- 在类内部调用事务方法,@Transactional不生效
- 把异常catch住处理掉了,没往上抛,@Transactional不生效
- 方法抛出的异常和rollbackFor指定的异常不匹配(rollbackFor不写的话默认RuntimeException)
- 新开线程执行DML,@Transactional不生效; (子线程抛出的异常父线程捕获不到,两个线程不在同一事务里面)
发布影响
发布评估 | 影响面 | 具体描述 |
---|---|---|
基建需求,如果涉及各业务线,需要各个业务线配合的务必提前沟通,不能因流程繁琐或主观认为影响小而跳过沟通环节 | 20250901 数据权限上线,导致部分GDS接口没有权限。 | 可以业务线配合,也可以延期,但是不能存在问题提前业务线验证,可最大程度避免问题 |
重点需求,线下先观察 | 20250820 数据权限上线,周末集中在 dev/tst/pre 验证,问题未被暴露,上线引发问题 | 预留一定的时间,用来做观察 |
发布评估清单(Checklist)
维度 | 评估项 |
---|---|
影响面 | 是否涉及多业务线? |
回滚成本 | 回滚是否影响数据一致性? |