我正在尝试使用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,因为它试图读取整个事情。有什么想法吗?
答案 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子句等。