简体   繁体   English

如何使用Spring MySQL和RowCallbackHandler管理大型数据集

[英]How to manage a large dataset using Spring MySQL and RowCallbackHandler

I'm trying to go over each row of a table in MySQL using Spring and a JdbcTemplate. 我正在尝试使用Spring和JdbcTemplate遍历MySQL中表的每一行。 If I'm not mistaken this should be as simple as: 如果我没记错的话,它应该很简单:

JdbcTemplate template = new JdbcTemplate(datasource);
template.setFetchSize(1);
// template.setFetchSize(Integer.MIN_VALUE) does not work either            
template.query("SELECT * FROM cdr", new RowCallbackHandler() {
  public void processRow(ResultSet rs) throws SQLException {
    System.out.println(rs.getString("src"));
  }
});

I get an OutOfMemoryError because it is trying to read the whole thing. 我收到一个OutOfMemoryError,因为它试图读取整个内容。 Any ideas? 有任何想法吗?

Here's a Spring solution based on the answer provided by BalusC. 这是基于BalusC提供的答案的Spring解决方案。

class StreamingStatementCreator implements PreparedStatementCreator {
    private final String sql;

    public StreamingStatementCreator(String sql) {
        this.sql = sql;
    }

    @Override
    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
        final PreparedStatement statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
        statement.setFetchSize(Integer.MIN_VALUE);
        return statement;
    }
}

Somewhere in your code: 在代码中的某处:

DataSource dataSource = ...;
RowCallbackHandler rowHandler = ...;
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.query(new StreamingStatementCreator("SELECT * FROM huge_table"), rowHandler);

The Statement#setFetchSize() javadoc already states: Statement#setFetchSize() javadoc已经声明:

Gives the JDBC driver a hint as to the number of rows that should be fetched from the database 向JDBC驱动程序提示应从数据库中获取的行数

The driver is actually free to apply or ignore the hint. 驱动程序实际上可以自由地应用或忽略提示。 Some drivers ignore it, some drivers applies it directly, some drivers needs more parameters. 一些驱动程序忽略它,一些驱动程序直接应用它,一些驱动程序需要更多参数。 The MySQL JDBC driver falls in the last category. MySQL JDBC驱动程序属于最后一类。 If you check the MySQL JDBC driver documentation , you'll see the following information (scroll about 2/3 down until header ResultSet ): 如果查看MySQL JDBC驱动程序文档 ,将看到以下信息(向下滚动约2/3,直到标题ResultSet为止):

To enable this functionality, you need to create a Statement instance in the following manner: 要启用此功能,您需要通过以下方式创建一个Statement实例:

 stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE); 

Please read the entire section of the document, it describes the caveats of this approach as well. 请阅读文档的整个部分,它也描述了这种方法的注意事项。

To get it to work in Spring, you'll however need to extend/override the JdbcTemplate with a custom implementation. 为了使其在Spring中工作,您需要使用自定义实现扩展/覆盖JdbcTemplate。 As I don't do Spring I can't go in detail about this, but now you at least know where to look. 由于我不从事Spring工作,因此无法对此进行详细介绍,但是现在您至少知道要看的地方了。

Good luck. 祝好运。

If you suspect you are getting the OutOfMemory error due to the entire table read, why dont you try splitting your query. 如果您怀疑由于读取整个表而收到OutOfMemory错误,为什么不尝试拆分查询。 Use filters, LIMIT clause etc. 使用过滤器,LIMIT子句等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM