¿Qué Java ORM puede darme SQL dinámico y control del ResultSet al mismo tiempo?

Requisitos para un ORM que busco:

  1. SQL dinámico con:

    1.1. Prevención de inyección SQL

    1.2. parámetros con nombre

    1.3. capacidad para establecer condicionalmente las condiciones de la cláusula where

    1.4. capacidad para llamar a procedimientos y funciones almacenados

  2. Me permite establecer parámetros importantes de ResultSet, como el tamaño de recuperación

  3. Me permite controlar cuándo cerrar el ResultSet

  4. Me permite iterar a través del resultado sin esperar a que se obtengan todas las filas de la conexión o ResultSet. Esto se debe a lo siguiente

    • habrá consultas que pueden devolver millones de filas (la paginación no se realizará en la base de datos usando rownum o select top)

    • No quiero esperar a que millones de filas se carguen primero en la memoria antes de poder comenzar a hacer algo con las filas que el ResultSet ya puede haber obtenido.

    • queremos controlar dónde y cuándo debemos dejar de obtener filas de la conexión o ResultSet mientras iteramos a través de las filas

Incluya algunos fragmentos de código para demostrar esto.

ACTUALIZAR:

Para (3), debería poder hacer esto sin tener que esperar a que se devuelva un solo registro. Si solo el ORM puede devolverme el conjunto de resultados y permitirme desplazarme manualmente por los registros permitiéndome llamar al .next(), encajaría perfectamente con lo que estoy buscando.

Tal vez solo estoy buscando una forma basada en plantillas para generar SQL (tan poderosa como MyBatis) que me permita simplemente pasar parámetros sin preocuparme por la inyección de SQL.

#4 está controlado por el controlador JDBC, no necesariamente por el código Java que itera sobre el ResultSet
@a_horse_with_no_name, el controlador JDBC respeta el tamaño de recuperación establecido. Una vez que la cantidad de filas obtenidas alcanza este número, resultSet.next() está disponible de inmediato, incluso si hay millones de filas en el resultado de la búsqueda que aún no se han obtenido. Esto es hasta donde me dice mi experiencia. Esto es cierto, al menos para Oracle JDBC.
Sí, el Oráculo se comporta de esa manera. Pero no todos los controladores JDBC hacen eso. Algunos almacenan en búfer todo el conjunto de resultados en la memoria de forma predeterminada.

Respuestas (1)

MyBatis cumple con la mayoría de sus requisitos.

  1. Consulte los documentos de Dynamic SQL y Mapper . Todos sus requisitos están ahí.
  2. Usando la propiedad fetchSize . Busque en los documentos para esto.
  3. Vea el método stop() en ResultContext como se menciona a continuación
  4. Busque el parámetro RowBounds en esta página en mybatis docs. Consulte esta respuesta de desbordamiento de pila para obtener más detalles.

De la documentación:

Finalmente, hay tres versiones avanzadas de los métodos de selección que le permiten restringir el rango de filas para devolver o proporcionar una lógica de manejo de resultados personalizada, generalmente para conjuntos de datos muy grandes.

<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)'

El parámetro RowBounds hace que MyBatis salte la cantidad de registros especificados, así como limita la cantidad de resultados devueltos a algún número. La clase RowBounds tiene un constructor para tomar tanto el desplazamiento como el límite y, por lo demás, es inmutable.

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

Diferentes conductores pueden lograr diferentes niveles de eficiencia en este sentido. Para obtener el mejor rendimiento, utilice tipos de conjuntos de resultados SCROLL_SENSITIVE o SCROLL_INSENSITIVE (en otras palabras: no FORWARD_ONLY).

El parámetro ResultHandler le permite manejar cada fila como quiera. Puede agregarlo a una lista, crear un mapa, un conjunto o descartar cada resultado y, en su lugar, mantener solo los totales acumulados de los cálculos. Puede hacer casi cualquier cosa con ResultHandler, y es lo que MyBatis usa internamente para crear listas de conjuntos de resultados.

La interfaz es muy simple.

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

El parámetro ResultContext le brinda acceso al objeto de resultado en sí, un recuento de la cantidad de objetos de resultado creados y un método booleano stop() que puede usar para evitar que MyBatis cargue más resultados.

para el n. ° 3, en realidad debería poder detener y cerrar la conexión sin siquiera tener que obtener al menos un registro en los casos en que la consulta lleva demasiado tiempo para obtener el primer registro. Supongo que no se llamará al controlador hasta que Oracle haya devuelto al menos un registro. ¿Hay alguna manera de obtener realmente el conjunto de resultados subyacente? Solo quería que myBatis construyera el SQL y me devolviera el conjunto de resultados