Procesamiento por lotes
Un enfoque ingenuo para insertar 100.000 filas en la base de datos usando Hibernate podría verse así:
Esto podría caer sobre una OutOfMemoryException en algún sitio
cerca de la fila 50.000. Esto es porque Hibernate tiene en caché todas las instancias
de Customer recién instanciadas en el caché de nivel de sesión.
En este capítulo te mostraremos cómo evitar este problema. Primero, sin embargo,
si estás haciendo procesamiento por lotes (batch processing), es absolutamente crítico
que habilites el uso de loteo JDBC, si pretendes lograr un rendimiento razonable.
Establece el tamaño de lote JDBC a un número razonable (digamos 10-50):
Podrías además querer hacer este tipo de trabajo en un proceso donde la interacción con el caché de
segundo nivel esté completamente deshabilitado:
Inserciones en lote
Al hacer persistentes objetos nuevos, debes limpiar con flush() y
llamar a clear() en la sesión regularmente, para controlar el tamaño
del caché de primer nivel.
Actualizaciones en lote
Para recuperar y actualizar datos se aplican las mismas ideas. Adicionalmente, necesitas usar
scroll() para sacar ventaja de los cursores del lado del servidor en consultas
que devuelvan muchas filas de datos.
update/delete en masa
Como ya se ha discutido, el mapeo objeto/relacional automático y transparente se refiere
al manejo de estado de objetos. Esto implica que el estado del objeto está disponible
en memoria, por lo tanto actualizar o borrar (usando UPDATE y
DELETE de SQL) datos directamente en la base de datos no afectará el
estado en memoria. Sin embargo, Hibernate provee métodos para la ejecución de sentencias
del estilo de UPDATE y DELETE de SQL que se realizan
a través del Lenguaje de Consulta de Hibernate (Hibernate Query Language o
HQL).
La pseudo-sintáxis para sentencias UPDATE y DELETE es:
( UPDATE | DELETE ) FROM? ClassName (WHERE WHERE_CONDITIONS)?. Algunos puntos
a tener en cuenta:
En la cláusula-from, la palabra clave FROM es opcional
Puede haber sólo una clase mencionada en la cláusula-from, y no puede
tener un alias.
No puede especificarse ningún join (bien implícito o explícito) en una consulta masiva de HQL.
Pueden usarse subconsultas en la cláusula-where.
La cláusula-where es también opcional.
Como un ejemplo, para ejecutar un UPDATE HQL, usa el
método Query.executeUpdate():
Para ejecutar un DELETE HQL, usa el mismo método Query.executeUpdate()
(el método está nombrado para aquellos familiarizados con
PreparedStatement.executeUpdate() de JDBC):
El valor int devuelto por el método Query.executeUpdate()
indica el número de entidades afectadas por la operación. Considera que esto puede o no
correlacionarse al número de filas afectadas en la base de datos. Una operación masiva HQL podría
resultar en que se ejecuten múltiples sentencias de SQL reales, para joined-subclass, por ejemplo.
El número devuelto indica el número de entidades reales afectadas por la sentencia. Volviendo al
ejemplo de joined-subclass, un borrado contra una de las subclases puede resultar realmente en
borrados contra no sólo la tabla a la que está mapeada esa subclase, sino también la tabla "raíz"
y potencialmente tablas de joined-subclass más debajo en la jerarquía de herencia.
Ten en cuenta que existen actualmente unas pocas limitaciones con las operaciones HQL masivas,
que serán atendidas en lanzamientos futuros; consulta la hoja de ruta de JIRA para más detalles.