Spring Поддержка JDBC и большой набор данных
При использовании одного из различных методов шаблона JDBC я смущен тем, как итерации/прокрутки больших наборов результатов (которые не будут вписываться в память). Даже без прямого воздействия на интерфейс Iterable я бы по крайней мере ожидал, что экземпляры RowCallbackHandler будут вызваны во время выполнения запроса не после его завершения (или переполнения кучи).
Я посмотрел на этот (который ничего не изменил для меня, несмотря на то, что он похож по духу на этот пост о переполнении стека) и на этот пост в форумах spring. Последнее, по-видимому, предполагает, что обработчик обратного вызова действительно должен вызываться, пока курсор извлекает данные. Однако мои тесты не показывают такого поведения.
База данных - это Oracle10g. Я использую драйвер 11.1.0.7.0-Production и spring 2.5.6.SEC01. Любые идеи о том, как перебирать результирующие множества, желательно, сохраняя логику отображения RowMapper и т.д.
Ответы
Ответ 1
Драйвер JDBC Oracle имеет надлежащую поддержку метода setFetchSize()
на java.sql.Statement
, который позволяет вам контролировать количество строк, которые драйвер будет извлекать за один раз.
Однако RowMapper
, используемый Spring, работает, читая каждую строку в памяти, получая RowMapper
для перевода его в объект и сохраняя каждый объект строки в одном большом списке. Если ваш результирующий набор огромен, то этот список станет большим, независимо от того, как JDBC извлекает данные строки.
Если вам нужно обрабатывать большие результирующие наборы, тогда RowMapper не масштабируется. Вместо этого вы можете использовать RowCallbackHandler
, а также соответствующие методы на JdbcTemplate. RowCallbackHandler
не определяет, как будут сохраняться результаты, оставляя их для вас, чтобы сохранить их.
Ответ 2
Вы можете использовать springjdbc-iterable:
CloseableIterator<MyObj> iter = jt.queryForIter("select ...", params, mapper);
Итератор будет автоматически закрыт при истощении или может быть закрыт вручную. Он будет работать только в пределах транзакций.
Отказ от ответственности: я написал эту библиотеку
Ответ 3
Это свойство драйвера/соединения, чтобы передать данные обратно вам или отправить его обратно в один кусок. Например, в SQL Server вы используете свойство SelectMethod
на URL-адресе подключения:
jdbc:microsoft:sqlserver://gsasql03:1433;DatabaseName=my_db;SelectMethod=direct
Значение direct
означает, что результаты должны прийти за один раз. Другой выбор cursor
, который позволяет указать, что вы хотите, чтобы соединение с потоком возвращалось к вам. Я не уверен, что такое аналог для источника данных Oracle, я боюсь
RowCallbackHandler
, безусловно, работает для меня.
Ответ 4
- Создайте собственную хранимую процедуру, которая расширяет
StoredProcedure
- Создайте
RowCallBackHandler
, который может обрабатывать каждую строку, по одному за раз.
- Объявите свои параметры. Если у вас есть набор результатов, сначала объявите это первым. Используйте класс
SqlReturnResultSet
и создайте его, используя RowCallBackHandler
- Объявить любые другие параметры
- Compile
- Я сделал шаги с 2 по 5 в конструкторе хранимой процедуры клиента
- Создайте карту, содержащую ваши входные параметры
- Выполнение хранимых процедур с входными параметрами
Я бы предоставил код, но в следующей статье содержится вся эта информация.
Вызов хранимых процедур с Spring шаблонами JDBC
Ответ 5
здесь хорошая библиотека для вытаскивания всех наборов java sql в память.
http://casperdatasets.googlecode.com
вы можете прокручивать/итерировать через набор данных, вы можете выпускать против него запросы и создавать индексы для оптимизации. он также реализует интерфейс java.sql.resultset, чтобы вы могли продолжать работать с результатами этого набора данных с минимальными chnages на ваш код jdbc.