Está en la página 1de 36

Hibernate

Disminuye la cantidad de cdigo usado. Simplifica la interaccin con la base de datos. Optimiza el acceso a la base de datos.

pablomonteserin.com

ORM

Object Relational Mapping. Se encarga de transformar las tablas en clases, los campos en propiedades y viceversa.

pablomonteserin.com

Clave primaria

Usando Hibernate: - es fundamental que las tablas tengan clave primaria. - no es posible modificar claves primarias.

pablomonteserin.com

Usaremos el plugin para eclipse: Hibernate Tools


Help -> Install new software -> (ojo!!!! no introducir esta url en el work with) add -> pegamos -> http://download.jboss.org/jbosstools/updates/development/indigo - Marcamos, dentro de JBoss Data Services: Hibernate Tools

pablomonteserin.com

Descargar las libreras de hibernate


http://hibernate.org/downloads
Enlace final: http://sourceforge.net/projects/hibernate/files/hibernate3/

pablomonteserin.com

Jar que hay que aadir


Los siguientes ejercicios son proyectos java comunes. Para cargar las libreras crearemos una carpeta lib dentro de los mismos y cargaremos las libreras de ah (botn derecho sobre el proyecto properties java build path libraries add Jar) hibernate-distribution-3.6.0.Final/Hibernate3.jar hibernate-distribution-3.6.0.Final/lib/jpa/* hibernate-distribution-3.6.0.Final/lib/required/* Mysqlconnector En total hay que aadir 9 jars.
pablomonteserin.com

hibernate.cfg.xml
Lo ms cmodo es copiarlo de otro proyecto, en vez de generarlo nosotros. Debe estar en la raz de la carpeta src.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.bytecode.use_reflection_optimizer">false</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.isolation">2</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.connection.pool_size">10</property> <property name="hibernate.connection.url">jdbc:mysql://localhost/pruebas</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.current_session_context_class">managed</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.show_sql">true</property> <mapping resource="com/cursos/Simple.hbm.xml" /> </session-factory> </hibernate-configuration> pablomonteserin.com

Nomenclatura de tablas cuando trabajemos con Hibernate


Las palabras del nombre de la tabla se separan con guin bajo. Luego hibernate cambiar dicho _ por la siguiente letra en mayscula. Ya que las tablas se convertirn en clases, se escriben en singular.

pablomonteserin.com

Configuracin de consola
Btn derecho sobre el paquete -> run as -> Run configurations -> Hibernate Console Configuration -> new configuration Pestaa Main Proyect: nombre del proyecto. Configuration file: setup y busco el archivo hibernate.cfg.xml de Configuracin. Pestaa ClassPath: Me aseguro de que estn cargadas las 9 libreras indicadas en la diapositiva anterior. Si cuando me creo un proyecto tengo las libreras en el classpath (en el caso de un proyecto web, en la carpeta lib), no ser necesario aadirlas en esta pestaa, puesto que ya estn en el classpath.

pablomonteserin.com

Hibernate Code Generation Configurations


Hay que estar en perspectiva Java. Icono con desplegable de Hibernate -> Hibernate Code Generation Configurations Pestaa Main: Console configuration: Selecciono la configuracin de consola previamente creada. Output directory -> NombreDelProyecto/src. Reverse engineer from JDBC Connection -> Marco la check Package: com.pablomonteserin.POJO Pestaa Exporters: Marco las checks Domain code, Hibernate XML Mappings, Hibernate XML Configuration. Run Esto crea una clase por cada tabla de mi base de datos, as como un get y set por cada columna.

pablomonteserin.com

Errores tpicos en la generacin de clases


Exception while generating code. Reason: java.lang.NullPointerException Todas las tablas deben tener clave primaria. Exception while generating code. Reason: org.hibernate.console.HibernateConsoleRuntimeException. Problems while loading database driver class(com.mysql.jdbc.Driver.) En runc run configurations Hibernate Console Configuration faltan por aadir las libreras de hibernate y el driver de mysql Exception while generating code. Reason: org.hibernate.tool.hbm2x.ExporterException: File pattern not set on class org..tool.hbm2x.GenericExporter En HibernateCodeGenerationConfigurations Exporters, marcar los exporters para los que est configurada la generacin: - Domain code (.java) - Generic Exporter (<hbmtemplate>) - Hibernate XML Configuration (.cfg.xml)

pablomonteserin.com

Mapeos de Hibernate en hibernate.cfg.xml


Las tablas de hibernate son mapeadas a ficheros *.hbm.xml. Si el archivo hibernate.cfg.xml tiene una referencia a dichos mapeos y no los encuentra fsicamente en el equipo, dar un error.

pablomonteserin.com

Hibernate API

http://docs.jboss.org/hibernate/core/3.5/javadocs/

pablomonteserin.com

Transacciones
Conjunto de operaciones contra la base de datos que se realizan de forma atmica (o todas o ninguna). Cuando nos interesa crear una transaccin? Cuando modificamos la base de datos (y por tanto deseamos poder hacer rollback()). Para una consulta no es necesario. Crear una transaccin consume recursos.

pablomonteserin.com

Ejemplo
SessionFactory, Session, Transaction
- La llamada a Configuration().configure() carga el fichero de configuracin hibernate.cfg.xml. - Normalmente, el ejemplar de SessionFactory slo se crea una vez y luego se utiliza para crear todas las sesiones relacionadas con un contexto dado. - Un objeto Session Hibernate representa una nica unidad-de-trabajo y es abierta por un ejemplar de SessionFactory. Se deben cerrar las sesiones cuando se haya completado todo el trabajo de una transacin. - En caso de fallo, lo que hay dentro del beginTransaction y el commit no se ejecuta y se salta a un catch. - Siempre es ms rpido hacer dos operaciones en una sola transaccin que dos operaciones en dos transacciones. public static void main(String[] args) { System.out.println("en Test1.main"); Autor a = new Autor(5, "autor1"); SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); session.beginTransaction(); session.save(a); session.getTransaction().commit(); session.close(); }

pablomonteserin.com

session.flush()
Este mtodo se asegura de que la informacin ha sido persistida en la base de datos, de forma que ya sea posible cerrar con seguridad la session. Este mtodo es ejecutado automticamente por session.close(), no obstante es recomendable que siempre lo ejecutemos explcitamente justo antes. Puede ser til hacer un flush para recuperar la id autoincrementada de un objeto recien insertado. Ejemplo: Session.save(persona); Session.flush(); Id = persona.getId();
pablomonteserin.com

Mtodos de la clase Session


session.save(persona) // guarda un objeto como registro en la base de datos. Session.refresh(persona) // en nos permitir conocer la id del objeto insertado, suponiendo que la id sea autoincrementada. session.update(persona); session.saveOrUpdate(persona);

session.get(Persona.class, id) -> me permite recuperar datos.

// el mtodo load lo usamos slo para borrar un paciente. ya que nos devuelve un paciente slo con la clave primaria seteada. Para recuperar todos los valores usaremos get. Persona personaABorrar = (Persona) session.load(Persona.class, idPaciente); session.delete(personaABorrar); pablomonteserin.com

Definir claves forneas con sql


El siguiente cdigo SQL genera una relacin 1 a muchos: ALTER TABLE libro ADD CONSTRAINT fk_autor FOREIGN KEY ( idAutor ) REFERENCES autor( id ) El cdigo para generar una relacin uno a uno sera igual, pero cambiando los nombres de los campos a los que hago referencia: ALTER TABLE autor ADD FOREIGN KEY ( id ) REFERENCES padre_autor (id) Nota: Para asignar las foreing keys es necesario que: - los tipos de datos de los campos relacionados coincidan. - Las tablas deberan estar vacas, u obtendremos un error del tipo "Table already exists". - El motor de las tablas sea InnoDB.

autor id nombre

libro id id_autor titulo


pablomonteserin.com

Ejercicio crear base de datos

autor id nombre

libro id n id_autor titulo


pablomonteserin.com

Crear una relacin n a n


Una relacin n a n son dos relaciones 1 a n vinculadas a una misma tabla auxiliar. MySQL WorkBench, desde la ventana de diagramas EER nos permite crear automticamente relaciones n a n, de forma que se crear automticamente la tabla intermedia.

pablomonteserin.com

Insertar slo un autor

public static void main(String[] args) { System.out.println("en Test1.main"); Autor a = new Autor("juan", new HashSet()); SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); session.beginTransaction(); session.save(a); session.getTransaction().commit(); session.close(); }

pablomonteserin.com

Insertar un autor y sus libros


public static void main(String[] args) { System.out.println("en Test1.main"); HashSet libros = new HashSet(); Autor a = new Autor("juan", libros); Libro l1= new Libro(7, a,"titulox11"); Libro l2= new Libro(8, a,"titulox22"); SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); session.beginTransaction(); session.save(a); session.save(l1); session.save(l2); session.getTransaction().commit(); session.close(); }

pablomonteserin.com

Save en Cascada
Habr que aadir el atributo cascade=all al set de libros de Autor.hbm.xml Set<Libro> libros = new HashSet<Libro>(); Autor a = new Autor("Robert",libros); libros.add(new Libro(33, a, "viajes1")); libros.add(new Libro(34, a, "viajes2")); libros.add(new Libro(35, a, "viajes3")); session.save(a); Nota: De esta forma, al borrar el autor, se borran tambin los libros.
pablomonteserin.com

Carga perezosa
Es una estrategia que consiste en demorar la carga de un objeto hasta que este sea requerido. Es decir, la carga del objeto se realiza de manera explcita cuando este es invocado. Lazy loading se utiliza en aquellos casos en los que la aplicacin necesita acceder solo a una parte de un objeto, a un subgrafo del objeto, o a algunos atributos de un objeto. En general la carga perezosa slo se utiliza en las colecciones 1-n y n-n. Est por defecto a lazy true. Es posible usar cargar perezosas en relaciones 1-1 pero no es sencillo ni frecuente. Podemos modificar el atributo lazy=true que encontraremos en los set de objetos (si los hubiese) de los ficheros .hbm.xml.

pablomonteserin.com

Ejercicio
Hacer una clase Main que contenga tres transacciones que realicen las siguientes operaciones: 1 Insertar cuatro libros. No hace falta hacerlo por cdigo java; insertar directamente los libros utilizando el gestor de la base de datos. 2 - Imprimir los libros del autor cuya clave primaria es tres. 3 Recuperar uno de los libros insertados y modificarlo.

pablomonteserin.com

Mtodos de la clase Criteria


Consultar una tabla Criteria crit = session.createCriteria(Autor.class); List result = crit.list(); crit.uniqueResult() Consultar un nico registro

Consultar toda la base de datos Criteria crit = session.createCriteria(java.lang.Object.class) Aadir restricciones crit.addOrder(Order.desc(''nombre'')); crit.add(Restrictions.eq(''nombre'', ''Juan'')); //Por defecto las restricciones se aaden con AND crit.add(Restrictions.like(''nombre'',''%ar%'')); //Para aadir una restriccin con OR crit.add(Restrictions.disjunction().add(Restrictions.like("nombre", "%c%"))); Nota: Utilizando Criteria no es necesario hacer commit().

pablomonteserin.com

Ejercicio
Insertar 5 libros en la base de datos. Dos registros deben tener el mismo ttulo (''titulo1''). Utilizar la clase criteria para mostrar los libros cuyo ttulo contenga la palabra ''titulo1''. Hacer una nueva consulta, ordenando la salida por el ttulo, e ir recorrindola imprimiendo los ttulos y las id con System.out.println();

ID:1 ID:6 ID:2 ID:4 ID:3

Ttulo:titulo1 Ttulo:titulo2 Ttulo:titulo3 Ttulo:titulo4 Ttulo:titulo5

pablomonteserin.com

Consulta con Example


Creamos un objeto (a) y haremos la consulta a partir de l. Si le pasamos null como parmetro el parmetro es ignorado. Autor a = new Autor("raque"); Example exampleAutor = Example.create(a); exampleAutor.ignoreCase(); exampleAutor.enableLike(MatchMode.ANYWHERE); exampleAutor.excludeProperty("id"); Criteria crit = session.createCriteria(Autor.class); crit.add(exampleAutor);
ANYWHERE END EXACT START Match the pattern anywhere in the string. Match the end of the string to the pattern. Match the entire string to the pattern. Match the start of the string to the pattern. pablomonteserin.com

Consulta simple Query hqlQuery = session.createQuery(''FROM Libro''); //recupero una coleccin de objetos Query hqlQuery2 = session.createQuery("SELECT v.matricula FROM Vehiculo v");//recupero un String en vez de un objeto List result = hqlQuery.list(); Consulta ordenada Query hqlQuery = session.createQuery(''FROM Libro ORDER BY id''); List result = hqlQuery.list(); Consulta con parmetro String queryString = from Libro where nombre like ?; Query hqlQuery = session.createQuery(queryString).setString(0, "%Ro%");

HQL

Consulta con parmetro II String queryString =FROM Hombre WHERE nombre LIKE: textSearch; Query hqlQuery = session.createQuery(queryString).setString("textSearch", "%o%"); Consulta en el hbm Consulta definida en un mapeo hbm.xml /*La siguiente consulta es recuperada del archivo Simple.hbm.xml. De todas formas, funcionara desde cualquier otro mapeo. En este caso, el cdigo presente en el mapeo es: <query name="findLibroByTitulo"> <![CDATA[ FROM Libro l WHERE l.titulo LIKE :textoBusqueda ]]> </query> */ Query hqlQuery = session.getNamedQuery("findLibroByTitulo").setParameter("textoBusqueda", "%a%"); List result = hqlQuery.list(); Eliminar un registro String queryString = "delete from Paciente where id=?"; Query hqlQuery = session.createQuery(queryString); hqlQuery.setInteger(0, 4); hqlQuery.executeUpdate();

pablomonteserin.com

Evitar inyeccin SQL


Se debe evitar crear consultas HQL concatenando Strings:
String queryString = "from item i where i description like ' " + search + " ' ";

En cambio es aconsejable usar:

Parmetros con nombre: String queryString = "from Simple where texto like :textSearch"; Parmetros posicionales: String queryString = "from Simple where texto like ?"; Query hqlQuery = session.createQuery(queryString); hqlQuery.setString(0, "%1%" );

pablomonteserin.com

Consulta relacionada
Evaluar si una propiedad del bean es igual a cierto valor (no funciona si la propiedad es un set) String queryString = '' from Libro l where l.autor.nombre like :textSearch''; Query hqlQuery = session.createQuery(queryString).setString(''textSearch'', ''%n%''); Evaluar si uno de los los elementos de la propiedad del bean consultado es igual a cierto valor String queryString = " select a from Autor a join a.libros l where l.titulo='titulox11'"; Query hqlQuery = session.createQuery(queryString); Nota: La siguiente lnea es equivalente a la lnea en verde (pero utilizando join): String queryString = "select l from Libro l join l.autor a where a.nombre='nombre1'"; Las palabras escritas en rojo son propiedades de las clases, no son campos de la base de datos.

pablomonteserin.com

Una consulta HQL que no debo hacer


select v.matricula, v.marca from Vehiculo v order by v.ruedas En el ejercicio siguiente veremos la forma correcta de hacer esta consulta para recuperar los valores deseados. Si ejecutamos esta consulta y pretendemos recorrera, estaramos recorriendo una lista de un array de Objects: List <Object[]>result = hqlQuery.list(); Iterator<Object[]> it = result.iterator(); while(it.hasNext()){ Object[] obj = it.next(); System.out.println("Matricula: "+ obj[0]); System.out.println("Marca: "+ obj[1]);
pablomonteserin.com

Ejercicio
No es un proyecto web. Realizar las siguientes consultas: - Listar las matrculas de todos los vehculos. - Listar la matrcula y la marca de todos los vehculos ordenados por nmero de ruedas. - Listar la matrcula de todos los vehculos que tengan ms de dos asientos y ms de dos ruedas. - Listar la matrcula de todos los vehculos que tengan ms de dos asientos o ms de dos ruedas. - Listar la matriula de todos los vehculos que tengan una matriula de menos de seis caracteres (where length(v.matricula)<?). - Listar la matrcula de todos los vehculos que hayan tenido un siniestro con valorPerdida mayor de 1000 euros. - Listar la matrcula de todos los vehculos que hayan tenido un siniestro con valorPerdida mayor de 1000 euros. Mostrar a cuanto ascendi la prdida. Almacenar el resultado de la la consulta en: - Una lista de listas de dos elementos; el primero ser un bean de Vehculo y el segundo un Integer. La siguiente lnea me devuelve una lista de listas de dos elementos; el primero ser un bean y el segundo un String. select new List(v, s.perdida) from Vehiculo... - Una lista de beans VehiculoSiniestro, que tendrn cada uno dos propiedades, Vehiculo e Integer. Habr que crear la clase VehiculoSiniestro con su correspondiente constructor. select new com.pablomonteserin.main.VehiculoSiniestro(v, s.perdida)

siniestro id (int) fecha (date) perdida (int) id_vehiculo (int)

1 n

vehiculo id (int) matricula (varchar 20) asientos (int) ruedas (int) marca (varchar) pablomonteserin.com

Recuperacin de la session para no tener que instanciar un SessionFactory cada vez que la necesite.
//Una clase final es una clase que no puede ser extendida final public class ConexionProviderSingleton { private static SessionFactory sessionFactory; private static Session session; //Para evitar que podamos instanciar el Singleton, hacemos su constructor privado private ConexionProviderSingleton(){} public static Session getSession(){ if(sessionFactory==null){ sessionFactory = new Configuration().configure().buildSessionFactory(); } if(session == null || !session.isOpen()) session = sessionFactory.openSession(); return session; }
Singleton: Es un objeto del que slo puede existir una instancia por aplicacin. Dicho objeto debe ser esttico. Lo recomendable es que el mtodo que devuelva dicho objeto esttico, tambin sea esttico.

} Para recuperar la sesin desde la clase servicio: Session session = ConexionProviderSingleton.getSession();

pablomonteserin.com

Gestin de excepciones
public class PacienteDAO { public void alta(Paciente paciente){ try{ Session session = ConexionProviderSingleton.getSession(); session.save(paciente); }catch(Throwable t){ //Ojo! Una vez subamos la aplicacin a produccin, no debe existir en ella ningn printStackTrace(); ya que no queremos cargar la consola del servidor con trazas. En su lugar usaremos log4j. Hay que tener en cuenta que printStackTrace() es un mtodo que devuelve void; por tanto no podremos volcarlo ntegro. //Capturo todas las excepciones que creo que pueden ocurrir y finalmente capturo Exception }catch(PropertyValueException e){ logger.error("ERROR. "+this.getClass().getCanonicalName()+". alta() paciente.id="+ paciente.getId()+"; " + e.getMessage()); //La siguiente excepcin ser la que llegar a la vista y ver el usuario de la aplicacin throw new DAOException("Ha habido un error al dar de alta paciente con id " + paciente.getId()); }catch(Exception e){ e.printStackTrace(); } } public class PacienteBO{ public void alta(Paciente paciente) { Session session = null; Transaction tx = null; try { session = ConexionProviderSingleton.getSession(); tx = session.beginTransaction(); pacienteDAO.alta(paciente); } catch (DAOException e) { logger.error("ERROR. "+this.getClass().getCanonicalName()+". alta() paciente.id="+ paciente.getId()+"; " + e.getMessage()); throw new BOException(this.getClass().getCanonicalName() + ". alta(): " + e.getMessage()); } tx.commit(); session.close(); } } En el controlador puedo redirigir a una pgina de error dnde pintara el mensaje de error, o pintarlo en alguna zona de la pgina en la que estoy, o mostrar un mensaje emergente, etc.

pablomonteserin.com

Hospital
La base de datos tendr 4 campos: id(PRIMARY KEY, AUTOINCREMENT), nombre (VARCHAR), apellidos (VARCHAR), fecha_alta(DATE).

pablomonteserin.com

También podría gustarte