Вопрос или проблема
Требования к ORM, которую я ищу:
-
Динамический SQL с:
1.1. предотвращение SQL-инъекций
1.2. именованные параметры
1.3. возможность условно устанавливать условия в операторе where
1.4. возможность вызывать хранимые процедуры и функции
-
Позволяет мне устанавливать важные параметры ResultSet, такие как размер выборки
-
Позволяет мне контролировать, когда закрывать ResultSet
-
Позволяет мне перебрать результат без ожидания, что все строки будут извлечены из подключения или ResultSet. Это связано со следующим:
-
будут запросы, которые могут вернуть миллионы строк (пагинация не будет выполняться в БД с использованием rownum или select top)
-
Я не хочу ждать, пока миллионы строк загрузятся в память прежде, чем смогу начать что-то делать со строками, которые уже могли быть извлечены ResultSet
-
мы хотим контролировать, где и когда мы должны остановить получение строк из подключения или ResultSet, перебирая строки
-
Пожалуйста, приведите несколько примеров кода, чтобы продемонстрировать это.
ОБНОВЛЕНИЕ:
Для (3) я должен иметь возможность сделать это, не дожидаясь возврата одной записи. Если только ORM сможет вернуть мне ResultSet и позволит вручную прокручивать записи, позволяя вызывать .next(), это будет идеально для того, что я ищу.
Может быть, я просто ищу основанный на шаблонах способ генерации SQL (такой же мощный, как MyBatis), который позволит мне просто передавать параметры, не беспокоясь о SQL-инъекциях.
MyBatis соответствует большинству ваших требований.
- Смотрите документацию по Динамическому SQL и Mapper. Все ваши требования там.
- Используйте свойство fetchSize. Поиск в документации по этому поводу.
- Смотрите метод stop() в ResultContext, как упомянуто ниже
- Ищите параметр 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
-
Динамическое создание 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>
-
Поддержка именованных параметров:
Как видно из приведенного выше примера, MyBatis использует имена параметров, которые автоматически связываются с полями объекта или значениями, переданными в метод. -
Условное формирование WHERE-клаузы:
Динамические конструкции<if>
и<where>
позволяют вам указывать условия выборки, которые формируются условно. Это особенно удобно, если количество фильтров может варьироваться. -
Вызов хранимых процедур и функций:
MyBatis поддерживает встроенные хранимые процедуры и функции, что позволяет вам легко интегрировать существующий функционал БД. -
Управление параметрами ResultSet:
Вы можете устанавливать параметры, такие как размер выборки (fetchSize), прямо в SQL-запросе. Это можно сделать через настройки маппинга.Пример:
sqlSession.selectList("findUsers", params, new RowBounds(offset, limit));
-
Контроль при закрытии ResultSet:
MyBatis предоставит управление жизненным циклом ResultSet, что означает, что вы можете закрывать его по своему усмотрению, пока освободили ресурсы после использования. -
Итерация результатов без ожидания полной выборки:
Вы можете использовать интерфейс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. Это решение поддерживает большие объемы данных и позволяет эффективно управлять ресурсами, что делает его отличным выбором для современных приложений, требующих высокой производительности и гибкости.
Если у вас есть дополнительные вопросы или требуется более детальное разъяснение, пожалуйста, не стесняйтесь обратиться.