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

时间:2010-01-19 17:25:46

标签: java mysql spring jdbc

我正在尝试使用Spring和JdbcTemplate遍历MySQL中的每一行表。如果我没弄错的话,这应该就像:

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"));
  }
});

我得到一个OutOfMemoryError,因为它试图读取整个事情。有什么想法吗?

3 个答案:

答案 0 :(得分:18)

这是一个基于BalusC提供的answer的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;
    }
}

代码中的某处:

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

答案 1 :(得分:9)

Statement#setFetchSize() javadoc已经声明:

  

为JDBC驱动程序提供提示关于应从数据库中提取的行数

驱动程序实际上可以自由应用或忽略提示。一些驱动程序忽略它,一些驱动程序直接应用它,一些驱动程序需要更多参数MySQL JDBC驱动程序属于最后一类。如果您选中MySQL JDBC driver documentation,则会看到以下信息(向下滚动约2/3直到标题 ResultSet ):

  

要启用此功能,您需要以下列方式创建Statement实例:

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

请阅读文档的整个部分,它也描述了这种方法的注意事项。

要使它在Spring中运行,您需要使用自定义实现扩展/覆盖JdbcTemplate。由于我不做春天,我不能详细说明这一点,但现在你至少知道在哪里看。

祝你好运。

答案 2 :(得分:0)

如果您怀疑由于整个表读取而导致出现OutOfMemory错误,为什么不尝试拆分查询。使用过滤器,LIMIT子句等。