Java RenderMergeDoutpModel中的OutOfMemoryError-从Spring MVC控制器返回大型对象

Java RenderMergeDoutpModel中的OutOfMemoryError-从Spring MVC控制器返回大型对象,java,spring-mvc,csv,out-of-memory,Java,Spring Mvc,Csv,Out Of Memory,我在SpringMVC应用程序中有一些代码,可以查询数据库并从结果集生成CSV文件。总体思路如下: @RequestMapping (value = "/path/to/the/data") public ModelAndView getDataAsCsv(...) { List<RowObject> bigObject; // can be > 1GB in memory bigObject = dataService.getData(...); Mo

我在SpringMVC应用程序中有一些代码,可以查询数据库并从结果集生成CSV文件。总体思路如下:

@RequestMapping
(value = "/path/to/the/data")
public ModelAndView getDataAsCsv(...) {
    List<RowObject> bigObject; // can be > 1GB in memory
    bigObject = dataService.getData(...);
    ModelAndView mav = new ModelAndView("dataCsvView");
    mav.addObject("bigObject", bigObject);
    return mav;
}
然后它继续迭代这个东西,将每一行转换成一个CSV字符串,并将其写入Spring的
HttpServletResponse#getWriter
方法中的
BufferedWriter

问题

如果数据集足够大(超过~500k行),则
bigObject
对象在内存中将>1GB。只要调用了
renderMergedOutputModel
,并试图从模型中取出对象,应用程序就会抛出OutOfMemoryError。或者,该错误可能发生在调用
renderMergedOutputModel
之前。无论哪种方式,将对象放入
mav
映射的行为都不是失败点(我已经检查过了)

一个解决方案是增加Tomcat进程的可用内存,但这显然不是非常可扩展的。。。(这些
bigObject
s将来可能会变得更大)


在SpringMVC中,“正确”的方法是什么?有没有一个好的体系结构可以让我们流式处理响应,而不必首先将其全部装入内存?

我不会使用
视图实现,而是自己编写
输出流,我会进行流式处理,而不是将所有内容加载到内存中。如何做到这一点取决于您的底层技术,但是使用
JdbcTemplate
我将实现一个
RowCallBackHandler
,它直接写入
Writer
(可能通过将其传递到服务方法)

或者在加载期间将CSV数据流式传输到一个文件,然后创建一个视图,将该文件流式传输到客户端(这样您就不必一直将所有内容都存储在内存中)。您只需要这样传递文件名

List<RowObject> bigObject = (ArrayList<RowObject>)model.get("bigObject");
public class CvsWritingRowCallbackhandler implements RowCallbackHandler {

    private final Writer writer;

    public CvsWritingRowCallbackhandler(Writer writer) {
        this.writer=writer;
    }

    public void processRow(ResultSet rs) throws SQLException {      
        String line = // do something with current row to create a Comma Seperated line
        writer.write(line);
                    writer.flush();
    }

}

public void someServiceMethod(final Writer writer) {
    getJdbcTemplate().query(query, new CvsWritingRowCallbackhandler(writer)); 
}

@RequestMapping
public void requestHandlingMethod(Writer writer) {
    someService.someServiceMethod(writer);
}