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

我正在尝试使用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,因为它试图读取整个事情。 有任何想法吗?

Statement#setFetchSize() javadoc已经声明:

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

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

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

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

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

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

祝你好运。

这是基于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; } } 

你代码中的某个地方:

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

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