如何避免OOM

一、背景

动态数据导出是一般项目都会涉及到的功能。它的基本实现逻辑就是从数据库查询数据,加载到内存,然后从内存创建excel或者csv,以流的形式响应给前端,通过浏览器下载到本地

然而一旦数据量太大,达到十万级,百万级,千万级,大规模数据加载到内存必然会引起OutofMemoryError

如何解决,本文提供了完整的解决方案

二、如何避免OOM

1、产品角度

我们为什么要导出这么多数据呢?这个设计是不是合理的呢?

如果要导出百万级数据,那为什么不直接找大数据或者DBA来干呢?然后以邮件形式传递不行吗?

如果通过分页导出,每次点击按钮只导几万条,分批导出难道不能满足业务需求吗?

如果产品缺个筋,听不懂你的话,坚持要一次性导出全量数据,那就只能从技术实现上考虑如何实现了

2、技术角度

不能将全量数据一次性加载到内存之中,这可以通过采用stream流方式实现

以csv代替excel,减少文件结构存储空间

三、基于Mybatis实现方案

1、书写Mapper

@Mapper

public interface UserMapper {

    List<User> getAllUserList();

}

1

2

3

4

2、书写XML文件

fetchSize表示每次读取数据1000条到内存

<mapper namespace="com.it.shw.oom.mapper.UserMapper">

    <select id="getAllUserList" resultType="com.it.shw.oom.entity.User" fetchSize="1000">

        SELECT * from tb_user

    </select>

</mapper>

1

2

3

4

5

3、书写结果集处理器

 public class UserResultHandler<T> implements ResultHandler<T> {

        // 每批处理的大小

        private final int batchSize;

        // 每批当前待处理数据个数

        private int count;

        // 存储每批数据的临时容器

        private List<T> results;

        // 处理器

        private final CallbackProcess callbackProcess;

    

        // 构造函数

        public UserResultHandler(CallbackProcess callbackProcess, int batchSize) {

            super();

            this.callbackProcess = callbackProcess;

            this.batchSize = batchSize;

            count = 0;

            results = new ArrayList<>();

        }

    

        @Override

        public void handleResult(ResultContext resultContext) {

            T resultObject = (T) resultContext.getResultObject();

            results.add(resultObject);

            count++;

            if (count == batchSize) {

                callbackProcess.processData(results);

                // 重置临时数据容器

                clear();

            }

        }

    

        // 用来完成最后一批数据处理

        public void end() {

            if (count > 0) {

                callbackProcess.processData(results);

                // 重置临时数据容器

                clear();

            }

        }

    

        // 重置临时数据容器

        public void clear() {

            count = 0;

            results.clear();

        }

    }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

4、书写回调过程

猜你喜欢

转载自www.cnblogs.com/jsbuxgs/p/12799812.html
OOM