Как управлять большим набором данных, используя Spring MySQL и RowCallbackHandler - PullRequest
7 голосов
/ 19 января 2010

Я пытаюсь просмотреть каждую строку таблицы в MySQL, используя Spring и JdbcTemplate. Если я не ошибаюсь, это должно быть так просто:

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 ]

18 голосов
/ 14 мая 2010

Вот решение Spring на основе ответа , предоставленного BalusC.

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);
9 голосов
/ 20 января 2010

Statement#setFetchSize() javadoc уже заявляет:

Предоставляет драйверу JDBC подсказку относительно количества строк, которые следует извлечь из базы данных

Водитель может свободно применять или игнорировать подсказку. Некоторые драйверы игнорируют его, некоторые драйверы применяют его напрямую, некоторым драйверам нужно больше параметров. Драйвер MySQL JDBC относится к последней категории. Если вы посмотрите документацию по драйверу MySQL JDBC , вы увидите следующую информацию (прокрутите примерно на 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 с помощью пользовательской реализации. Поскольку я не делаю Spring, я не могу подробно рассказать об этом, но теперь вы, по крайней мере, знаете, где искать.

Удачи.

0 голосов
/ 19 января 2010

Если вы подозреваете, что получаете ошибку OutOfMemory из-за чтения всей таблицы, почему бы вам не попробовать разбить ваш запрос. Используйте фильтры, предложение LIMIT и т. Д.

...