Обработка больших записей в приложении Java EE - PullRequest
2 голосов
/ 02 февраля 2010

Существует таблица phonenumbers с двумя столбцами: id и number. В таблице около half a million entries. База данных MySQL.

Требуется разработать простое приложение Java EE, подключенное к этой базе данных, которое позволит пользователю загружать все значения number в comma separated style, следуя определенному URL-адресу.

Если мы получим все значения в огромном String array, а затем объединим их (с запятой между всеми значениями) в String и затем отправим их пользователю, это будет правильным решением?

Приложение не является общедоступным и будет использоваться ограниченным числом. людей.

Ответы [ 3 ]

8 голосов
/ 02 февраля 2010

Лучше всего , а не хранить данные в памяти Java любым способом, а просто записывать полученные данные в ответ немедленно по мере поступления данных. Вам также необходимо настроить драйвер JDBC MySQL для построчного обслуживания результирующего набора на Statement#setFetchSize() согласно документации драйвера JDBC MySQL , в противном случае он будет кешировать все в памяти. 1010 *

Предполагая, что вы знакомы с сервлетами, вот базовый пример, который учитывает все это:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/plain");
    response.setHeader("Content-Disposition", "attachment;filename=numbers.txt"); // Force download popup.

    Connection connection = null;
    Statement statement = null;
    ResultSet resultSet = null;
    Writer writer = response.getWriter();

    try {
        connection = database.getConnection();
        statement = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
        statement.setFetchSize(Integer.MIN_VALUE);
        resultSet = statement.executeQuery("SELECT number FROM phonenumbers");

        while (resultSet.next()) {
            writer.write(resultSet.getString("number"));
            if (!resultSet.isLast()) {
                writer.write(",");
            }
        }
    } catch (SQLException e) {
        throw new ServletException("Query failed!", e);
    } finally { 
        if (resultSet != null) try { resultSet.close; } catch (SQLException logOrIgnore) {}
        if (statement != null) try { statement.close; } catch (SQLException logOrIgnore) {}
        if (connection != null) try { connection.close; } catch (SQLException logOrIgnore) {}
    }
}
1 голос
/ 02 февраля 2010

Существует немного больше для правильного форматирования вывода CSV. Было бы проще использовать существующую библиотеку, такую ​​как эта , для генерации выходного файла.

Вы можете сгенерировать вывод в файл на диске (на веб-сервере), а затем перенаправить браузер в этот файл (с помощью задания cron или чего-либо еще, чтобы очистить старые данные) или просто передать результат непосредственно обратно пользователю.

Если вы используете потоковую передачу напрямую, убедитесь, что для MIME-типа задано значение, которое будет запускать загрузку в браузере пользователя (например, text / csv или text / отделенные запятыми значениями)

0 голосов
/ 02 февраля 2010

Если бы использовать Mysql 5.1+, я бы просто использовал проприетарный синтаксис, чтобы куда-нибудь вывести файл и передать его в ответе сервлета.

SELECT a,b,a+b INTO OUTFILE '/tmp/result.txt'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM test_table;

http://dev.mysql.com/doc/refman/5.1/en/select.html

Для стольких записей, если вы все еще хотите использовать JDBC, вы можете попробовать следующее:

  • получить количество записей, получить несколько записи (используя запрос предел) и напишите их
  • если вы достигнете числа записи в чанке, вы получаете другой один, пока вы не достигнете максимума количество записей
...