专栏首页强仔仔如何高效的处理第三方接口数据?

如何高效的处理第三方接口数据?

很多公司业务都需要进行第三方接口的对接工作,特别是那种大部分数据都来自第三方的项目。比如亚马逊商家服务的saas系统,基本上所有的数据都来自亚马逊平台。

背景

像这种需要定期获取亚马逊接口数据,然后存储到本地数据库中的项目,一般就会涉及到数据转换过程。这边我将会给大家介绍一个实际项目案例,平台从亚马逊获取数据,进行解析的过程中,因为数据过大,导致内存溢出的场景。

接口说明

亚马逊平台返回的是json格式数据,然后通过jackson进行json解析,将最后的解析结果保存到我们自己的数据库中。但是json反序列也是需要技巧的,否则会因为使用不当导致内存溢出。

json解析

一开始我们通过jackson工具类,将json流解析为JsonNode,如下所示:

ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree((GZIPInputStream) reportMap.get("data"));

但是当请求量过大的时候,内存中就会出现大量的LinkHashMap、Entry、HashMap、Node之类的集合对象,时间一长就OOM内存溢出了。

解析改造

集合对象如果没有管理好,会很难被GC回收,所以一开始我们想到的办法是将JsonNode设置为null,后面发现这样做没起到任何作用,所以只能进行彻底的改造,直接用jackson解析成我们需要的对象,如下所示:

private List<ReportAdvertisementDto> parseJsonIO(GZIPInputStream gzipInputStream) {
ObjectMapper mapper = new ObjectMapper();
List<ReportAdvertisementDto> advertisementDtoList =new ArrayList<>();
try {
    advertisementDtoList = mapper.readValue(gzipInputStream, new TypeReference<List<ReportAdvertisementDto>>() {
            });
} catch (IOException e) {
    logger.error("parseJsonIO转化异常,错误信息为:{}", ExceptionUtil.formatException(e));
}
return advertisementDtoList;
}

修改完之后可以很明显的看到,LinkHashMap、Entry、HashMap、Node之类的对象数量大量减少,内存的占用率明显降低,大大的减少了内存OOM的风险。

深入改造

写到这一步是不是就优化完毕了呢?不!!!一开始的时候我是将所有的字段全部设置为String,然后通过Long.value()和Integer.value()转换为数据库需要的字段类型,如下所示:

campaignSearchTermReport.setImpressions(Integer.valueOf(impressions));
campaignSearchTermReport.setTotalspend(Long.valueOf(cost));
campaignSearchTermReport.setSales(BigDecimal.valueOf(sales));

所以为了避免这种情况发生,我们需要将转换的对象字段提前设置好,数据库需要什么类型,我们就设置为同样的类型,这样的好处就是我们不需要进行转型,直接就可以set进去,如下所示:

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ReportAdvertisementDto {
    private double cost;
    private String attributedSales1d;
    private int impressions;
    private int clicks;
    private long campaignId;
    private String campaignName;
    private String adGroupName;
    private long adId;
    private long adGroupId;
    private String sku;
    private String asin;
    private long keywordId;
    private String matchType;
    private String query;
    private String keywordText;
    private int attributedConversions7d;
    private double attributedSales7d;
    private int attributedUnitsOrdered7d;
    private int attributedConversions7dSameSKU;
    private double attributedSales7dSameSKU;
}

总结

在数据量不大的情况下,代码就算效率不高,也不会出现什么问题,但是当数据量达到一定级别,代码问题就会被凸显出来。比如我们平时用Map来存储临时数据,但是map集合的大小要比对象更加占用内存,如果服务器硬件不高,很容易就发生内存溢出。 所以我们在处理接口数据的时候,一定要本着简单、适用。尽量不要将json数据解析为map等集合,对象字段尽量设置为和入库的的表字段类型一致,减少转型的发生。禁止出现大量对象和对象之间数据流转,尽量做到一个解析后的对象直接入库,不需要进行任何转型操作。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【SpringBoot系列】static修饰的字段如何获取application.yml配置

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

    林老师带你学编程
  • 如何优雅的解决n 1查询!!!

    我们在写代码的时候非常忌讳出现n+1次查询,这就意味的你的循环有多少次,就会查询多少次数据库,这是很恐怖的场景。

    林老师带你学编程
  • 使用Docker容器搭建MySql主从复制

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

    林老师带你学编程
  • 既然Java反射可以访问和修改私有成员变量,那封装成private还有意义么?

    安全是指不让代码被非法看到/访问。但是只要人能拿到代码,总会有办法去查看和改变代码。其他答案提到反射可以用SecurityManager来防止private被访...

    大宽宽
  • 聊聊SimpleCanalConnector的getWithoutAck

    本文主要研究一下SimpleCanalConnector的getWithoutAck

    codecraft
  • 聊聊SimpleCanalConnector的getWithoutAck

    本文主要研究一下SimpleCanalConnector的getWithoutAck

    codecraft
  • Android实现轮询的三种方式

    砸漏
  • NullException、Token的作用、Mapstruct用法

    token主要用在会话管理,防止表单提交和防止CSRF攻击,同时token支持跨域访问,无状态,不存储session信息。

    关忆北.
  • Spring OAuth框架下增加用户属性的注意事项

    当我们修改了用户中心的dao、mapper后,需要注意的是,即便鉴权中心没有修改任何东西也一定要重新编译打包,因为修改了公共模块,否则鉴权中心无法识别AppUs...

    算法之名
  • Android实现伴奏录音合成MP3

    本文实例为大家分享了Android实现伴奏录音合成MP3的具体代码,供大家参考,具体内容如下

    砸漏

扫码关注云+社区

领取腾讯云代金券