Какой Java ORM может предоставить мне как динамический SQL, так и контроль над ResultSet одновременно?

Вопрос или проблема

Требования к ORM, которую я ищу:

  1. Динамический SQL с:

    1.1. предотвращение SQL-инъекций

    1.2. именованные параметры

    1.3. возможность условно устанавливать условия в операторе where

    1.4. возможность вызывать хранимые процедуры и функции

  2. Позволяет мне устанавливать важные параметры ResultSet, такие как размер выборки

  3. Позволяет мне контролировать, когда закрывать ResultSet

  4. Позволяет мне перебрать результат без ожидания, что все строки будут извлечены из подключения или ResultSet. Это связано со следующим:

    • будут запросы, которые могут вернуть миллионы строк (пагинация не будет выполняться в БД с использованием rownum или select top)

    • Я не хочу ждать, пока миллионы строк загрузятся в память прежде, чем смогу начать что-то делать со строками, которые уже могли быть извлечены ResultSet

    • мы хотим контролировать, где и когда мы должны остановить получение строк из подключения или ResultSet, перебирая строки

Пожалуйста, приведите несколько примеров кода, чтобы продемонстрировать это.

ОБНОВЛЕНИЕ:

Для (3) я должен иметь возможность сделать это, не дожидаясь возврата одной записи. Если только ORM сможет вернуть мне ResultSet и позволит вручную прокручивать записи, позволяя вызывать .next(), это будет идеально для того, что я ищу.

Может быть, я просто ищу основанный на шаблонах способ генерации SQL (такой же мощный, как MyBatis), который позволит мне просто передавать параметры, не беспокоясь о SQL-инъекциях.

MyBatis соответствует большинству ваших требований.

  1. Смотрите документацию по Динамическому SQL и Mapper. Все ваши требования там.
  2. Используйте свойство fetchSize. Поиск в документации по этому поводу.
  3. Смотрите метод stop() в ResultContext, как упомянуто ниже
  4. Ищите параметр RowBounds на этой странице в документации mybatis. Смотрите ответ на Stack Overflow для получения дополнительных сведений.

Согласно документации:

Наконец, есть три расширенные версии методов select, которые
позволяют ограничить диапазон возвращаемых строк или предоставить пользовательскую
логику обработки результатов, обычно для очень больших наборов данных.

<E> List<E> selectList (String statement, Object parameter, RowBounds rowBounds)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)
void select (String statement, Object parameter, ResultHandler<T> handler)
void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler<T> handler)'

Параметр RowBounds заставляет MyBatis пропустить указанное количество записей,
а также ограничить количество возвращаемых результатов до некоторого
числа. У класса RowBounds есть конструктор, принимающий как смещение,
так и лимит, и он в остальном неизменен.

int offset = 100;
int limit = 25;
RowBounds rowBounds = new    RowBounds(offset, limit);

Разные драйверы способны достигать разных уровней эффективности
в этом отношении. Для наилучшей производительности используйте типы наборов результатов
SCROLL_SENSITIVE или SCROLL_INSENSITIVE (другими словами: не
FORWARD_ONLY).

Параметр ResultHandler позволяет вам обрабатывать каждую строку так, как вам
угодно. Вы можете добавить ее в список, создать карту, множество или просто игнорировать каждый
результат и вместо этого хранить только сводные итоги вычислений.
Вы можете делать практически все с ResultHandler, и именно это
MyBatis использует внутренне для построения списков наборов результатов.

Интерфейс очень простой.

package org.apache.ibatis.session;
public interface ResultHandler<T> {
  void handleResult(ResultContext<? extends T> context);
}

Параметр ResultContext предоставляет доступ к самому объекту результата,
количеству созданных объектов результата и методу Boolean
stop(), который вы можете использовать, чтобы остановить MyBatis от загрузки каких-либо дополнительных
результатов.

Ответ или решение

Для решения вашей задачи по выбору Java ORM, который обеспечит как динамическое создание SQL-запросов, так и контроль над объектом ResultSet, рассмотрим MyBatis. Этот фреймворк станет идеальным решением для реализации ваших требований благодаря своей гибкости и мощным возможностям.

Основные требования и их выполнение с помощью MyBatis

  1. Динамическое создание SQL с защитой от SQL-инъекций:
    MyBatis позволяет вам формировать динамические SQL-запросы с использованием XML- или аннотационных подходов. Например, вы можете легко реализовать динамические условия в SQL, используя <if>, <choose>, <when> и другие конструкции, что защитит вас от инъекций.

    Пример:

    <select id="findUsers" parameterType="map" resultType="User">
       SELECT * FROM users
       <where>
           <if test="name != null">
               AND name = #{name}
           </if>
           <if test="age != null">
               AND age = #{age}
           </if>
       </where>
    </select>
  2. Поддержка именованных параметров:
    Как видно из приведенного выше примера, MyBatis использует имена параметров, которые автоматически связываются с полями объекта или значениями, переданными в метод.

  3. Условное формирование WHERE-клаузы:
    Динамические конструкции <if> и <where> позволяют вам указывать условия выборки, которые формируются условно. Это особенно удобно, если количество фильтров может варьироваться.

  4. Вызов хранимых процедур и функций:
    MyBatis поддерживает встроенные хранимые процедуры и функции, что позволяет вам легко интегрировать существующий функционал БД.

  5. Управление параметрами ResultSet:
    Вы можете устанавливать параметры, такие как размер выборки (fetchSize), прямо в SQL-запросе. Это можно сделать через настройки маппинга.

    Пример:

    sqlSession.selectList("findUsers", params, new RowBounds(offset, limit));
  6. Контроль при закрытии ResultSet:
    MyBatis предоставит управление жизненным циклом ResultSet, что означает, что вы можете закрывать его по своему усмотрению, пока освободили ресурсы после использования.

  7. Итерация результатов без ожидания полной выборки:
    Вы можете использовать интерфейс ResultHandler, который позволит вам обрабатывать каждый результат по мере его получения. Это особенно полезно для больших объемов данных, когда вы можете обрабатывать результаты по одному, не дожидаясь загрузки всех строк.

    Пример:

    sqlSession.select("findUsers", params, new ResultHandler<User>() {
       @Override
       public void handleResult(ResultContext<? extends User> context) {
           User user = context.getResultObject();
           // Обработайте пользователя
           if (shouldStopProcessing()) {
               context.stop(); // Остановите дальнейшую выборку
           }
       }
    });

Заключение

MyBatis — очень мощный инструмент, который удовлетворяет всем вашим требованиям, включая динамическое создание SQL, защиту от инъекций и возможность управления ResultSet. Это решение поддерживает большие объемы данных и позволяет эффективно управлять ресурсами, что делает его отличным выбором для современных приложений, требующих высокой производительности и гибкости.

Если у вас есть дополнительные вопросы или требуется более детальное разъяснение, пожалуйста, не стесняйтесь обратиться.

Оцените материал
Добавить комментарий

Капча загружается...