Обработка очень большого количества данных в 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, поддерживая.