Обработка очень большого количества данных в MyBatis
Моя цель - фактически сбросить все данные базы данных в файл XML. База данных не очень большая, ее около 300 МБ. Проблема в том, что у меня ограничено ограничение памяти на 256 МБ (только в JVM). Поэтому, очевидно, я не могу просто прочитать все в памяти.
Мне удалось решить эту проблему с помощью iBatis (да, я имею в виду iBatis, а не myBatis), называя его getList(... int skip, int max)
несколько раз, с приращением skip
. Это решает мою проблему с памятью, но меня не впечатляет скорость. Имена переменных указывают на то, что метод, находящийся под капотом, состоит в том, чтобы прочитать весь набор результатов, пропустив указанную запись. Это звучит довольно излишне для меня (я не говорю, что метод делает, я просто догадываюсь о базе имени переменной).
Теперь я перешел на myBatis 3 для следующей версии моего приложения. Мой вопрос: есть ли лучший способ обработать большой объем данных куском в myBatis? В любом случае, чтобы myBatis обрабатывал первые N записей, возвращайте их вызывающему, сохраняя соединение с набором результатов открытым, поэтому в следующий раз, когда пользователь вызывает getList (...), он начнет чтение из записи N + 1, не делая никаких "пропуск"?
Ответы
Ответ 1
Нет, mybatis не имеет полной возможности для потока результатов.
РЕДАКТИРОВАТЬ 1:
Если вам не нужны вложенные сопоставления результатов, вы можете реализовать собственный обработчик результатов для потока результатов. на текущие выпущенные версии MyBatis. (3.1.1) Текущее ограничение - это когда вам нужно выполнить сложное отображение результатов. NestedResultSetHandler не разрешает обработчики пользовательских результатов. Исправление доступно, и похоже, что в настоящее время он предназначен для 3.2. См. Проблема 577.
В общем, для потоковой передачи больших наборов результатов с использованием MyBatis вам понадобится.
- Внедрить собственный ResultSetHandler.
- Увеличить размер выборки. (как указано ниже Гийомом Перро)
- Для карт с вложенными результатами используйте исправление, обсуждаемое в Issue 577. Это исправление также устраняет некоторые проблемы с памятью с большими наборами результатов.
Ответ 2
myBatis CAN-поток. Вам нужен пользовательский обработчик результатов. При этом вы можете взять каждую строку отдельно и записать ее в свой XML файл. Общая схема выглядит следующим образом:
session.select(
"mappedStatementThatFindsYourObjects",
parametersForStatement,
resultHandler);
Где resultHandler - это экземпляр класса, реализующего интерфейс ResultHandler. Этот интерфейс имеет только один метод handleResult
. Этот метод предоставляет вам объект ResultContext. Из этого контекста вы можете получить прочитанную строку и сделать с ней что-то.
handleResult(ResultContext context) {
Object result = context.getResultObject();
doSomething(result);
}
Ответ 3
handleResult получает столько записей, сколько получает запрос, без паузы.
Когда слишком много записей для обработки, я использовал sqlSessionFactory.getSession(). getConnection().
Затем, как обычный JDBC, получите инструкцию, получите набор результатов и обработайте по одному записи. Не забудьте закрыть сеанс.
Ответ 4
Если просто сбросить все данные без какого-либо требования к порядку из таблиц, почему бы не сделать прямое разбиение на страницы в SQL? Задайте ограничение для оператора запроса, где указывается другой идентификатор записи как смещение, чтобы разделить всю таблицу на куски, каждый из которых может быть непосредственно прочитан в память, если ограничение строк является разумным числом.
В sql может быть что-то вроде:
SELECT * FROM resource
WHERE "ID" >= continuation_id LIMIT 300;
Я думаю, что это можно рассматривать как альтернативное решение для того, чтобы вы сбросили все данные кусками, избавляясь от различных проблем с функциями в mybatis или любом уровне Persistence, поддерживая.