我瞥了一眼他的代码:用 HttpClient 调接口写了 50 行配置,定义 3 个实体类解析 JSON,MyBatis 的 XML 里全是<if test>判断 null 值,测试的时候插错数据还得手动删库 —— 这不纯纯给自己找罪受吗?
最后我给他换了套方案,代码砍到原来的 1/5,不仅没再报错,连测试都省了一半时间。今天就把这套 “接口数据入库最优解” 分享出来,尤其适合天天跟第三方接口打交道的同学。
其实这事儿我踩过不少坑,从刚工作到现在试过 5 种方案,最后才找到最顺手的组合:
不是我吹,最后这套方案让我上个月少加了至少 30 小时班 —— 尤其是处理带 null 值的接口数据时,简直是救星。
先交代背景:我要解决的问题很简单 —— 调用第三方接口拿 JSON 数据,解析后批量塞进 MySQL。但里面坑不少:接口字段时增时减、总有几个字段返回 null、数据量大了插得巨慢、测试还容易搞脏数据库。
试了一圈发现,把这几个工具搭起来刚好能填上所有坑:
以前用 HttpClient,光设置超时、header、连接池就写满一屏代码,还总忘关流导致内存泄漏。
现在用 Hutool 的 HttpUtil,一行代码搞定:
// 就这一行,自动处理超时、编码、Cookie
String json = HttpUtil.get("http://第三方接口地址", 5000);最香的是重试机制 —— 接口偶尔抽风时,加个循环重试比 HttpClient 配拦截器简单 10 倍:
// 三次重试机制,再也不用手动改代码重跑了
for (int i = 0; i < 3; i++) {
try {
return HttpUtil.get(url, 5000);
} catch (Exception e) {
if (i == 2) throw new RuntimeException("接口崩了");
}
}这是我最想吐槽的点:第三方接口字段天天变,今天加个phone,明天删个address,实体类改得比代码还勤。
现在用 JSONUtil 直接转成 List,字段随便变:
// 一行代码解析,Map的key就是字段名,不用管接口怎么变
List<Map<String, Object>> dataList = JSONUtil.toList(json, Map.class);同事之前不信,说 “这能处理 null 值?”—— 还真能,不过得加个小技巧(后面说)。
MyBatis 的<foreach>标签我真是写吐了,尤其是字段多的时候,XML 里字段和值对齐能看瞎眼。
现在用 Hutool.Db,表名 + Map 列表直接插,连 SQL 都不用写:
// 表名+数据列表,一行搞定批量插入
Db.use().insertBatch("user", dataList);以前用 main 方法测试,插错一次数据就得登数据库删半天,现在用 Spring 的测试框架:
最开始用默认连接池,10 万条数据插了 40 分钟,以为是代码问题,换了 Druid 后 8 分钟搞定 —— 原来连接池对性能影响这么大。
直接上干货,这套流程我在 3 个项目里验证过,从几百条到 10 万级数据都稳得一批。
// 超时时间5秒,自动处理编码和异常
String json = HttpUtil.get("http://第三方接口地址", 5000);// 直接转成Map列表,字段变了也不用改
List<Map<String, Object>> rawData = JSONUtil.toList(json, Map.class);这里要注意:如果有的行有age字段,有的没有,直接插入会报 “字段数量不匹配”。
解决办法是统一所有行的字段,缺失的补 null:
// 收集所有可能的字段
Set<String> allFields = new HashSet<>();
rawData.forEach(row -> allFields.addAll(row.keySet()));
// 确保每行都有所有字段,没有的补null
List<Map<String, Object>> dataList = new ArrayList<>();
for (Map<String, Object> row : rawData) {
Map<String, Object> newRow = new HashMap<>();
allFields.forEach(field -> newRow.put(field, row.get(field)));
dataList.add(newRow);
}// 分批次插,1000条一批防止内存爆了
List<List<Map<String, Object>>> batches = CollUtil.split(dataList, 1000);
for (List<Map<String, Object>> batch : batches) {
Db.use().insertBatch("user", batch);
}就这四步,比原来的代码量少了至少 80%,关键是接口怎么变都不用改代码了。
说几个实际开发中最爽的点:
当然也不是没缺点:如果是特别复杂的业务(比如插入前要关联 5 张表),可能还是得用 MyBatis 写自定义 SQL,但这种场景真的不多。
我见过太多人把简单的事情复杂化:为了 “规范” 用一堆框架,结果配置比业务代码还多;为了 “可扩展性” 加一堆抽象类,结果从来没扩展过。
处理接口数据入库这种场景,真的不用搞那么复杂 —— 工具是为了提高效率,不是为了炫技。
这套方案我用了大半年,帮 3 个同事优化过代码,反馈都是 “再也不用加班改实体类了”。
最后问一句:你们公司是怎么处理第三方接口数据的?有没有比这更爽的方案?欢迎在留言区交流~