Manual usuario lista paginada

Anuncio
FRAMEWORK ATLAS
MANUAL DE BUENAS PRÁCTICAS CON HIBERNATE
Versión 1.0
UNIDAD DE ARQUITECTURA DE SOFTWARE DE APLICACIONES
DIRECCIÓN DE INGENIERIA
Hoja de Control
Título
Manual de buenas prácticas con Hibernate
Responsable
Arquitectura Software de Aplicaciones
Versión del Framework
ATLAS 1.2.9
Versión del documento
1.0
Fecha Versión
29/01/2016
Registro de Cambios
Versión
Causa del Cambio
Versión
framework
Fecha
1.0
Versión inicial del documento
1.2.9
10/12/2015
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
1
DIRECCIÓN DE INGENIERIA
Índice
1
INTRODUCCIÓN ...............................................................................................................................................3
1.1
1.2
2
CUANDO USAR LAS DISTINTAS FORMAS DE CONSULTA DE DATOS CON HIBERNATE ..........4
2.1
2.2
2.3
2.4
2.5
3
AUDIENCIA OBJETIVO ............................................................................................................................3
CONOCIMIENTOS PREVIOS ....................................................................................................................3
NAVEGACIÓN POR EL ÁRBOL DE OBJETOS ....................................................................................................4
CUANDO USAR LA INTERFAZ CRITERIA DE HIBERNATE ...............................................................................5
CUANDO USAR ATLASQUERY.......................................................................................................................5
CUANDO USAR CONSULTAS HQL .................................................................................................................6
CUANDO USAR CONSULTAS SQL DE ORACLE ..............................................................................................7
PROBLEMA DEL N+1 EN HIBERNATE .......................................................................................................8
3.1
SOLUCIÓN AL PROBLEMA N+1 CON LEFT JOIN FETCH .................................................................................9
4
LLAMADA A PROCEDIMIENTOS ALMACENADOS..............................................................................10
5
PROCEDIMIENTOS ALMACENADOS QUE DEVUELVEN UN CURSOR ...........................................11
6
USO DE LA SESIÓN DE HIBERNATE.........................................................................................................12
7
USO DE SQL NATIVO ....................................................................................................................................12
8
USO DE NAMED PARAMETES ....................................................................................................................13
9
CONSULTAS EN BATCH CON HIBERNATE ............................................................................................14
9.1
USO DE LA CLASE ATLASPROCESOBATCHDB............................................................................................14
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
2
DIRECCIÓN DE INGENIERIA
1 INTRODUCCIÓN
Este documento contiene instrucciones y buenas prácticas para el uso Hibernate.
1.1 AUDIENCIA OBJETIVO
Este documento está orientado a toda aquella persona que esté desarrollando una aplicación Web basada en el
Framework Atlas.
1.2 CONOCIMIENTOS PREVIOS
Para un completo entendimiento del documento, el lector deberá tener conocimientos previos sobre las
siguientes tecnologías:
Lenguaje SQL
Lenguaje HQL (Hibernate Query Language)
Hibernate criterias
Configuración de Hibernate
Java
Se recomienda la lectura del libro Java Persistence with Hibernate, Editorial Manning, Autor Christian Bauer y
Gavin King.
Además es imprescindible conocer la documentación oficial de Hibernate
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/index.html
En particular el capítulo dedicado al rendimiento.
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
3
DIRECCIÓN DE INGENIERIA
2 Cuando usar las distintas formas de consulta de datos con Hibernate
Desde Hibernate existen varias maneras de acceso a datos.
Navegación en el árbol de objetos
Mediante Hibernate Criteria Interface
Mediante las clase AtlasQuery de ATLAS
Mediante consultas HQL (Hibernate Query Language)
Mediante consultas SQL Nativas
En cada caso de uso de las aplicaciones se deberá valorar y planear cual es la mejor técnica y estrategia para
recuperar los objetos de la consulta necesaria para el caso de uso, teniendo en cuenta minimizar el número de
Querys sobre las base de datos.
2.1 Navegación por el árbol de objetos
Siempre que se pueda, para acceder a un objeto se debe usar acceso por clave primaria. Esto es una cosa obvia.
Lo que hay que tener en cuenta es que si el objeto ya cargado tiene una relación con una lista de objetos, al
acceder mediante el arbol de objetos a esa lista, Hibernate en ese momento habrá otra query para cargar la lista
siguiente de objetos.
Esto no es un problema cuando, como en el ejemplo siguiente se está accediendo a un único objeto.
Ejemplo de consulta correcta mediante el árbol de objetos
Profesor profesor = this.facade.findProfesor(idProfesor);
for (Asignatura asignatura : profesor.getAsignaturas()) {
System.out.println("\t" + asignatura);
}
En este caso Hibernate lanzará 2 querys. Una para obtener el profesor y otra para obtener las asignaturas.
Aunque se podría hacer una consulta para obtenerlo de una vez, es una práctica aceptable.
Esto es un problema si se van a recorrer una lista de objetos y de esta a su vez obtener otra lista de objetos.
Ejemplo de consulta INCORRECTA mediante el árbol de objetos
Profesor profesor = this.facade.findProfesor(idProfesor);
for (Asignatura asignatura : profesor.getAsignaturas()) {
for (Alumno alumno : asignatura.getAlumnos()) {
System.out.println("\t" + alumno.getNombre());
}
}
En este caso se harán muchas más querys de las imprescindible lo cual puede causar un problema de
rendimiento. En este caso se realizará una query para obtener el profesor, otra para obtener las asignaturas, y
por cada asignatura se hará otra query para obtener los alumnos de esa asignatura. En este caso es mucho más
óptimo utilizar Criterias o HQL para en una sola consulta obtener todos los alumnos de las asignaturas de un
profesor.
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
4
DIRECCIÓN DE INGENIERIA
2.2 Cuando usar la Interfaz Criteria de Hibernate
El Api de Hibernate de Criteria permite construir una query estableciendo las restricciones dinámicamente y en
tiempo de ejecución.
En la parte de negocio de la aplicación, es decir cuando se están haciendo consultas para luego hacer
modificaciones, procesado, validación de los datos de las entidades, etc, lo recomendable es usar los propios
criterias de Hibernate (o la clase AtlasQuery de Atlas).
Ejemplo:
En una aplicación de expedientes, en la pantalla que se están creando un expediente, validando los datos
del expediente que introduce el usuario, danto de alta varias actuaciones para un expediente, etc, es
recomendable usar los criterias de Hibernate para tener un acceso muy cómodo a los datos mediante los
objetos de domino que devuelven los criterias y las facilidades de objetos mapeados en otros objetos, etc.
Además, en este caso el código generado es muy claro y mantenible.
2.3 Cuando usar AtlasQuery
La clase AtlasQuery existente dentro del Framework ATLAS es una clase de ayuda para la creación de
Criterias de Hibernate. A esta clase se le van diciendo los criterions, joins, proyeccciones etc que va a
tener una consulta y al final se usa el método toHibernateCriteria para generar un criteria con todas las
características indicadas. El uso de esta clase es cómodo y es recomendado para consultas sencillas, pero no es
obligatorio su uso. Tampoco cubre el 100% de las consultas que se podrían hacer usando los criterias de
Hibernate. Existe un manual llamado ATLAS_MUS_AtlasQuery.pdf que explica el uso de esta clase.
Si la consulta a realizar es muy complicada entonces será mejor usar directamente Criterias de Hibernate o HQL.
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
5
DIRECCIÓN DE INGENIERIA
2.4 Cuando usar consultas HQL
HQL es un dialecto orientado a objetos del lenguaje SQL. Este lenguaje es comúnmente usado para recuperación
de objetos, no para actualizaciones, inserciones o borrado de datos.
En las pantallas de consulta, donde exista una pantalla que muestra una serie de registros (Listas Paginadas), que
se obtienen de una consulta a varias tablas relacionadas es muy recomendable usar HQL.
Causas por las que es recomendable:
1. Haciendo una consulta con criterias de Hibernate o con AtlasQuery (y si no se usan proyeccciones), la
consulta final que ejecuta Hibernate en HQL se trae todos los campos de todas las tablas relacionadas,
cuando lo más probable es que en la lista de campos a mostrar sólo se muestren unos cuantos
2. Si la consulta con criterias no se hace correctamente (usando correctamente los join y los fetch mode en
los criterias) es posible que Hibernate ejecute muchas queries de SQL para una sola consulta o criteria. Es
el proveedor el que debe preocuparse de mirar las queries que realmente se están lanzando en una
consulta, para ver si se debe optimizar el criteria, o como es el caso que estamos describiendo hacer una
consulta con HQL
Ejemplo:
Tenemos una pantalla en el que queremos mostrar en una lista paginada: Nombre de los alumnos,
asignaturas y curso de la asignatura. Tenemos:
La BBDD que tenemos para obtener estos 3 campos tiene que hacer una query de 5 tablas (por
ejemplo)
La tabla alumnos tiene 30 campos, la asigturas 15 y la curso 6.
Haciéndolo con un Criteria de Hibernate o con un AtlasQuery obtendríamos una query que pediría al menos 51
campos (30+16+6) de los que sólo vamos a usar 3.
Además si el criteria no está correctamente formado. Por ejemplo no se han hecho correctamente los join con el
fetch mode join, es posible que Hibernate haga una query para obtener los alumnos a mostrar, y luego por cada
alguno obtenido haga otra query para obtener las asignaturas. Con lo cual esto no es lo más óptimo en una
pantalla de consulta. Ver el apartado “Problema del N+1 en Hibernate” para más información.
En este caso sería mucho más óptimo hacer una HQL que sólo se traiga los 3 campos a mostrar y haga las joins y
los where que necesite para hacer esa consulta.
No sólo en las listas páginadas es recomendable usar HQL, sino en cualquier consulta que con Criterias se vuelva
muy complicada o aquellas en las que no queramos obtener más que sólo unos cuantos campos de las tablas
involucradas en la consulta.
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
6
DIRECCIÓN DE INGENIERIA
2.5 Cuando usar consultas SQL de Oracle
En principio no es recomendable usar directamente consultas SQL a no ser que sea porque una query concreta se
detecte que tarde mucho y haya que optimizarla haciendo una consulta SQL compleja. La optimización se haría
directamente en el gestor de BBDD y luego se trasladaría la query al código de la aplicación.
Hay que tener en cuenta que este tipo de queries pueden ser muy dependientes del gestor de BBDD, y en algunos
casos incluso de la versión usada en el Gestor de BBDD. (Oracle 9, Oracle 11g…)
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
7
DIRECCIÓN DE INGENIERIA
3 Problema del N+1 en Hibernate
Uno de los mayores problemas de los ORM en general y de Hibernate en particular es el problema llamado de los
“n+1” SELECTs.
Este problema consiste en que al lanzar una consulta que retorna n filas, el ORM lanza n+1 consultas SQL de
SELECT. Como podemos imaginar esto genera unas pérdidas de rendimiento brutales y consumo excesivo de CPU
por parte de las aplicaciones.
Veamos ahora un ejemplo con Hibernate de este problema.
Ejemplo de consulta INCORRECTA con HQL – EjemploDao.java
List<Profesor> profesores = getHibernateTemplate().find("SELECT p FROM Profesor p");
for (Profesor profesor : profesores) {
System.out.println(profesor.toString());
for (CorreoElectronico correoElectronico : profesor.getCorreosElectronicos()) {
System.out.println("\t"+correoElectronico);
}
}
Este código lo único que hace es mostrar todos los profesores, y para cada profesor mostrar todas sus direcciones
de correo. Esto lo hemos realizado lanzado únicamente una consulta HQL contra Hibernate.
Al ejecutar el programa y comprobar las SELECTs de SQL que se han lanzado podemos ver como se lanza una
primera consulta para obtener todos los profesores pero posteriormente se lanza una consulta adicional por cada
profesor para obtener los correos electrónicos de cada profesor. Es decir que se ejecutan ”n+1” SELECTs siendo
”n” el número de filas que retorna la primera consulta, en nuestro caso el número de profesores.
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
8
DIRECCIÓN DE INGENIERIA
3.1 Solución al problema N+1 con Fetch
La solución más sencilla es decirle a Hibernate que también cargue todos los correos electrónicos en la misma
query, para ellos deberemos hacer lo siguiente: En HQL deberemos hacer un la join utilizando FETCH en la Join a
realizar entre los profesores y los correos electrónicos.
La consulta HQL que realiza el LEFT JOIN FETCH entre los profesores y los correos electrónicos es la siguiente:
Ejemplo de consulta correcta con HQL
List<Profesor> profesores = getHibernateTemplate()
.find("SELECT p FROM Profesor p LEFT JOIN FETCH p.correosElectronicos ");
for (Profesor profesor : profesores) {
System.out.println(profesor.toString());
for (CorreoElectronico correoElectronico : profesor.getCorreosElectronicos()) {
System.out.println("\t"+correoElectronico);
}
}
Si ejecutamos ahora el código podremos ver en la consola que se ha lanzado únicamente la
siguiente SELECT de SQL, con lo que se ha solucionado el problema.
Query ejecutada por Hibernate
SELECT profesor0_.Id AS Id0_0_, correosele1_.IdCorreo AS IdCorreo1_1_,
profesor0_.nombre AS nombre0_0_, profesor0_.ape1 AS ape3_0_0_,
profesor0_.ape2AS ape4_0_0_, correosele1_.direccionCorreo AS direccio2_1_1_,
correosele1_.idProfesor AS idProfesor1_1_, correosele1_.idProfesor AS idProfesor0_0__,
correosele1_.IdCorreo AS IdCorreo0__
FROM Profesor profesor0_
LEFT OUTER JOIN CorreoElectronico correosele1_ ON profesor0_.Id=correosele1_.idProfesor
Atención
Si se están usando Criterias de Hibernate (o la clase AtlasQuery), este problema no está
solucionado para las consultas con innerJoin.
Es decir aunque se espeficique para los Criteria con innerJoin un FetchMode.JOIN se
seguirá produciendo el problema del N+1
Para estos casos hay que usar siempre HQL para optimizar las consultas
Referencia: https://hibernate.atlassian.net/browse/HHH-7842
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
9
DIRECCIÓN DE INGENIERIA
4 Llamada a procedimientos almacenados
La llamada a procedimientos almacenados se hará mediante la clase doWork() de Hibernate, de forma que no hay
que pedir la sesión actual. Ejemplo de uso:
EjemploDAO.java
/**
* Valida un documento de identidad llamando a un procedimiento
* almacenado en la BBDD
*
* @param documento a validar
* @return resultado de la validación del documento
* @throws DataAccessException
*/
public String validaDocumento(final String documento) throws DataAccessException {
class WorkImpl implements Work {
private String resultado;
public void execute(Connection connection) throws SQLException {
CallableStatement statement = null;
try {
statement = connection.prepareCall(
"{call sis_proc_ident_cod(?, ?)}");
statement.setString(1, documento.toUpperCase());
statement.registerOutParameter(1, java.sql.Types.VARCHAR);
statement.registerOutParameter(2, java.sql.Types.VARCHAR);
statement.executeQuery();
resultado = statement.getString(1);
}
finally {
if (statement != null) {
statement.close();
}
}
}
}
// Creamos el work y lo ejecutamos para devolver el resultado
WorkImpl work = new WorkImpl();
try {
getHibernateTemplate().getSessionFactory().
getCurrentSession().doWork(work);
return work.resultado;
} catch (Exception e) {
throw new DataAccessException("Error validando documento " + documento, e);
}
}
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
10
DIRECCIÓN DE INGENIERIA
5 Procedimientos almacenados que devuelven un cursor
Si uno de los parámetros de salida del procedimiento almacenado es un SYS_REFCURSOR de Oracle este es un
ejemplo de cómo leerlo usando un doWork():
EjemploDAO.java
/**
* Obtiene los módulos de una aplicación.
* El tercer parámetro del procedimiento almacenado es un cursor de Oracle
*
* @param codigoAplicacion
* @return lista de objetos ModulosApp
* @throws DataAccessException
*/
public List<ModulosApp> obtenerModulosAplicacion (final String codigoAplicacion) throws
DataAccessException {
class WorkImpl implements Work {
private List<ModulosApp> listaResultado =
new ArrayList<ModulosApp>();
public void execute(Connection connection) throws SQLException {
ResultSet rs = null;
CallableStatement statement = null;
try {
statement = connection.prepareCall(
"{call CONSULTA_MODULOS(?,?,?) }");
statement.setString(1, codigoAplicacion);
statement.registerOutParameter(2, java.sql.Types.VARCHAR);
statement.registerOutParameter(3,
oracle.jdbc.OracleTypes.CURSOR);
statement.execute();
//Recuperamos cursor
rs = (ResultSet) statement.getObject(3);
while (rs.next()) {
ModulosApp modulos = new ModulosApp();
modulos.setCdaplic(rs.getString("CDAPLIC"));
modulos.setDsaplic(rs.getString("DSAPLIC"));
...
...
listaResultado.add(modulos);
}
} finally {
if (rs != null) {
rs.close(); // Importante cerrar el cursor de Oracle
}
if (statement != null) {
statement.close();// Cerrar el statement
}
}
}
}
//Creamos el work y lo ejecutamos para devolver la lista de módulos
WorkImpl work = new WorkImpl();
try {
getHibernateTemplate().getSessionFactory().
getCurrentSession().doWork(work);
return work.listaResultado;
} catch (Exception e) {
throw new DataAccessException(
"Error recuperando módulos de la aplicación " + codigoAplicacion, e);
}
}
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
11
DIRECCIÓN DE INGENIERIA
6 Uso de la sesión de Hibernate
En la medida de lo posible se debe evitar el uso de la sesión de Hibernate. Para el caso de los procedimientos
almacenados se debe hacer como se explica en el apartado correspondiente, mediante el uso de doWork.
En el caso de que sea imprescindible obtener la sesión se hará desde un DAO y con el siguiente código.
EjemploDao.java
public List<Object[]> getQueryData() {
…
Session sesion = getHibernateTemplate().getSessionFactory().
getCurrentSession();
…
}
7 Uso de SQL Nativo
En el caso de utilizar SQL se implementará mediante los mecanimos que proporciona Hibernate para la ejecución
de queries SQL nativas (createSQLQuery)
EjemploDao.java – Ejemplo de uso de SQL Nativo
public List<Object[]> getClientesConNombre(String nombre) {
String sql = ("SELECT nombre, apellido1 FROM clientes where nombre = :nombre");
SQLQuery query = getHibernateTemplate().getSessionFactory().
getCurrentSession().createSQLQuery(sql);
query.setString("nombre", nombre);
return query.list();
}
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
12
DIRECCIÓN DE INGENIERIA
8 Uso de Named Parametes
Por motivos de optimización y seguridad de las consultas es necesario que los parámetros utilizados como
criterios no se adjunten en el String de la consulta y sean pasados como ‘named parameters’.
A continuación se muestra un ejemplo incorrecto y otro correcto de creación de consultas:
Creación INCORRECTA de consultas
String strQuery = "from Cliente where nombre = '" + nombre + "'"; // MAL
Query query = getHibernateTemplate()getSessionFactory().
getCurrentSession().createQuery(strQuery);
return query.list();
Creación CORRECTA de consultas
String strQuery = "from Cliente where nombre = :nombre"; // BIEN
Query query = getHibernateTemplate()getSessionFactory().
getCurrentSession().createQuery(strQuery);
query.setString("nombre", nombre);
return query.list();
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
13
DIRECCIÓN DE INGENIERIA
9 Consultas en BATCH con Hibernate
Cuando se necesita hacer un proceso en Batch sobre un número muy grande de registros, un error muy común
usando Hibernate que es: Primero hacer la query o criteria para obtener la lista de entidades y luego hacer un
bucle para tratar cada una de las entidades.
Al hacerlo de esta forma la lista de entidades primero se carga en memoria, con lo que si la query devuelve
200.000 registros (por ejemplo), lo primero que hace la aplicación es cargar esos 200.000 registros en memoria y
esto puede dar muy facilmente errores de falta de memoria en la máquina virtual.
Para evitar este problema hay que hacer uso de algunas funcionalidades que ofrece Hibernate como son:
Activar la propiedad hibernate.jdbc.batch_size en la sesión
.setCacheMode(CacheMode.IGNORE) en los criteria
.scroll(ScrollMode.FORWARD_ONLY)en los criteria
session.flush() y session.clear()
Desde el Framework ATLAS se ha creado una clase de ayuda para realizar el proceso de muchos registros en Batch
llamada AtlasProcesoBatchBD.java.
Atención
Si se está usando una versión de ATLAS anterior a la 1.2.9 solicitar la clase
AtlasProcesoBatchDB.java a Arquitectura para añadirla en el proyecto manualmente
9.1 Uso de la clase AtlasProcesoBatchDB
Los pasos a seguir son los siguientes
1. Configurar las propiedades de hibernate para poner que los registros se procesen en lotes (en principio de
50) y quitar la caché de segundo nivel de Hibernate
2. Crear en la capa de servicios un objeto que implemente la interface AtlasProcesarEntidadBD<T>
y sobreescribir el método altasProcesarEntidadBD en el que se pondrá la lógica para procesar
una entidad o registro.
3. Crear en la capa de DAO un método para procesar la tabla que reciba por parámetro el método creado
anteriormente, que cree la query para leer todo el fichero a procesar y que llame al método
AtlasProcesoBatchBD.ejecutarProcesoEntidadBD que es el que procesará los registros de
la query sin cargarlos previamente todos en memoria
4. Desde la capa de servicios hacer un método que llame a método del DAO creado en el punto anterior
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
14
DIRECCIÓN DE INGENIERIA
A continuación se muestra un ejemplo:
Modificaciones en el fichero applicationContext-database.xml
<property
<props>
<prop
<prop
<prop
<prop
<prop
<prop
<prop
name="hibernateProperties">
key="hibernate.dialect">${hibernate.dialect}</prop>
key="hibernate.show_sql">false</prop>
key="hibernate.format_sql">false</prop>
key="hibernate.use_sql_comments">false</prop>
key="hibernate.cache.use_second_level_cache">false</prop>
key="hibernate.cache.use_query_cache">false</prop>
key="hibernate.cache.region.factory_class">
atlas.core.cache.AtlasCacheRegionFactory</prop>
key="hibernate.cache.region_prefix"></prop>
key="net.sf.ehcache.configurationResourceName">ehcache.xml</prop>
key="atlas.cache.debugListener">false</prop>
key="hibernate.jdbc.batch_size">50</prop>
<prop
<prop
<prop
<prop
</props>
</property>
Javadoc de la clase de ayuda AtlasProcesoBatchBD.java
/**
* Clase de ayuda para realizar procesamiento por lotes en base de datos en el
* framework Atlas
* @author ICM
*/
public class AtlasProcesoBatchBD {
/**
* Interfaz que habrá a implementar para realizar el procesamiento batch
* dada una query de cada una de los objetos que recupera
*/
public interface AtlasProcesarEntidadBD<T> {
/** Método a sobreescibir **/
public void altasProcesarEntidadBD(T t);
}
/**
* Método de ayuda para procesar un query grande y llamar a un proceso por
* cada entidad de la query
*/
public static <T> void ejecutarProcesoEntidadBD(Session session, Query query,
AtlasProcesarEntidadBD<T> proceso, boolean readonly) throws Exception {
}
}
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
15
DIRECCIÓN DE INGENIERIA
Ejemplo ProcesaUnCliente.java
public class ProcesaUnCliente implements AtlasProcesarEntidadBD<Cliente>{
/**
* Fichero destino donde escribir los clientes
*/
private PrintWriter pw;
/**
* Constructor con los parámetros necesarios para procesar una entidad
* @param pw
*/
public ProcesaUnCliente(PrintWriter pw) {
this.pw = pw;
}
/**
* Método a sobreescribir que procesa una entidad del query
*/
@Override
public void altasProcesarEntidadBD(Cliente cliente) {
…
… <código para procesar un cliente> …
…
}
Ejemplo ClienteDao.java
public void procesaClientes(ProcesaUnCliente procesaUnCliente,
Map<String, Object> parametrosFiltro){
//Crear la query necesaria para recorrer el fichero a tratar
StringBuilder strQuery = new StringBuilder("from Cliente c ");
Query query = getSessionFactory().getCurrentSession().
createQuery(strQuery.toString());
for (Map.Entry<String, Object> entry : parametrosFiltro.entrySet()){
query.setString(entry.getKey(), (String) entry.getValue());
}
try {
AtlasProcesoBatchBD.ejecutarProcesoEntidadBD(
getSessionFactory().getCurrentSession(),
query,
procesaUnCliente,
true); // readonly
} catch (Exception e) {
LOG.error("Error procesando tabla de clientes: " + e.getMessage());
throw new DataAccessException(e);
}
}
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
16
DIRECCIÓN DE INGENIERIA
Ejemplo ClienteService.java
public File generarFicheroClientes(String sNombreFichero) throws ServiceException {
..,
try {
writer = new FileWriter(sNombreFichero);
pw = new PrintWriter(writer);
getDao().procesaClientes(
new ProcesaUnCliente(pw), //Tratamiento cada entidad
filtro); //parámetros de la query
} catch (IOException io) {
...
}
finally{
//Se cierra el fichero
pw.close();
...
}
}
Framework: ATLAS: Manual de buenas prácticas con Hibernate
Versión: 1.0
Fecha: 29/01/2016
17
Descargar