Hibernate - JPA @luce 5

Preview:

DESCRIPTION

Last session of the Hibernate course, about embedded, locking behaviour, inheritance... 5/5

Citation preview

Hibernate / JPA @luce5

Embedded

Embedded

• Clases que no tienen relación directa con una tabla (están contenidas dentro de otra tabla)o Ejemplo clásico: Usuario y dirección.

• Para mapear, @Embeddable para indicar que una clase se puede incluir dentro de otra y @Embedded para incluir dentro de una clase.

• Añadid dirección a las solicitudeso @Embeddable a la clase dirección (en vez de @Entity)o y @Embedded en el atributo dirección dentro de solicitud.

Modos de identidad

Modos de identidad

• Identidad de Tabla:o @Ido Compuesto:

Varios @Id @EmbeddedId (clase con @Embeddable y referencia con

@EmbeddedId) Id en otra clase y @IdClass en la tabla

• Probad cualquiera de estas referencias.

Modos de identidad

• Por favor, usad una clave subrogada.

• Las claves compuestas sólo dan problemaso Pueden no ser inmutableso Los requisitos cambian y afectan a las claveso Son menos eficientes (ocupan más)o Son menos uniformeso Son incómodas en Java (varios setters)o Son peores en Hibernate

Modos de identidad

• Generación:o Identidad (DB2, MySQL, SQL Server...)o Secuenciao Tabla (hi/lo a una tabla)o Autoo 14 algoritmos más

• En base a @GeneratedValue y seleccionando la estrategia y el generador (@SequenceGenerator, entre otros).

• Probad @SequenceGenerator para ver las opciones de configuración.

Modos de identidad

• Además de un @Id puedes definir que una columna es un Id Natural:o … @NaturalId

o buscar por natural id bySimpleNaturalId

Modos de identidad

• ¿Qué es la identidad?o Identidad de la BDo Identidad de Java

• Para una MISMA sesión, las dos cosas son lo mismo.• Y fuera? Hibernate no garantiza igualdad.

Modos de identidad

• Esto es importante en un par de casos sólo:o Composite Primary Key Classo 2 instancias de la misma clase en un Set en sesiones diferentes

• Implementa equals y hashCode, teniendo en cuenta que dos objetos diferentes pueden representar el mismo objeto en la base de datos.

Modos de identidad

• Repetimos...o Si usas primary keys compuestaso O si quieres unir entidades detached (luego veremos que es...) que reúsas

en un Set

• Deberías implementar equals y hashCode:o Comparando por igualdad de negocio (columnas y valores que identifican

univocamente a una entidad)• https://community.jboss.org/wiki/EqualsAndHashCode

Modos de locking

Modos de locking

• Hasta ahora, sin saberlo, estamos trabajando con un modo last commit wins.

• Cuando vamos a trabajar con algo, Hibernate recupera la entidad de la base de datos. Si cuando guardamos los datos han cambiado, ese usuario pierde esa información.

• Podemos trabajar de forma optimista, al guardar Hibernate comprueba que no se han tocado las cosas.

• Si se han tocado da un error, si no, sigue con su trabajo.

Modos de locking

• Para activarlo, sólo tenemos que definir un atributo de tipo Integer anotado con @Version.o Podemos usar un Date también

• Probadlo!

• En cualquier momento podemos llamar a un lock pesimista con session.lock()• [Avanzado] Si tenéis tiempo... bloquead la inserción de una tabla.

Herencia

Herencia

• Estrategiaso Tabla por clase concreta

Con polimorfismo implícito Con uniones

o Tabla por jerarquía de claseso Tabla por subclaseo Relaciones polimórficas

• + combinaciones de las anteriores• JPA no soporta todo lo que soporta Hibernate

Tabla por clase concreta con polimorfismo implícito

Tabla por clase concreta con polimorfismo implícito

• Es simple, consultar contra clases concretas• Contrapartidas…

o Polimorfismo Requiere una consulta por cada subclase concreta Las asociaciones no se representan bien (no aceptan una FK simple)

o Semánticas compartidas entre tablaso El esquema relacional no “conoce” la relacióno No se puede hacer una asociación hacia la abstracta (ya que no es una

entidad)

Tabla por clase concreta con polimorfismo implícito

@MappedSuperclass

public abstract class AbstractPago

@Entity

public class PagoPAC extends AbstractPago

@Entity

public class PagoBeca extends AbstractPago

Tabla por clase concreta con uniones

Tabla por clase concreta con uniones

• Permite relaciones hacia la clase abstracta

• Consultas optimizables por el SGBD

• Contrapartidas…o El esquema relacional no “conoce” la relación

Tabla por clase concreta con uniones

@Entity

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

public abstract class AbstractPago

@Entity

public class PagoPAC extends AbstractPago

@Entity

public class PagoBeca extends AbstractPago

Tabla por jerarquía

Tabla por jerarquía

• La mejor para el polimorfismo y para no polimorfismo

• Contrapartidas…

o Requiere columnas nullables en las subclases

o Posible desperdicio de espacio

o Requiere discriminador

Tabla por jerarquía

@Entity

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

@DiscriminatorColumn(name="tipo",

discriminatorType=DiscriminatorType.STRING)

public abstract class AbstractPago

@Entity

@DiscriminatorValue("PAC")

public class PagoPAC extends AbstractPago

@Entity

@DiscriminatorValue("beca")

public class PagoBeca extends AbstractPago

Tabla por subclase

Tabla por subclase

• Basada en FKs

• Esquema normalizado

• Contrapartidas…o Complica el esquemao Ineficiente en jerarquías complejas*o Clase padre concreta

Tabla por subclase

@Entity

@Inheritance(strategy = InheritanceType.JOINED)

public abstract class AbstractPago

@Entity

public class PagoPAC extends AbstractPago

@Entity

public class PagoBeca extends AbstractPago

Limitaciones de herencia

• Limitaciones oficiales

• Implementad alguna!o session.createCriteria(Petition.class) .list();

Relaciones polimórficas

• Permite mapear relaciones que no se podrían de otra forma: asociaciones polimórficas a clases desde múltiples tablas

• Sólo para situaciones muy especiales

• Contrapartidas…o No puede establecer FKso Envers no lo soporta ☹

Relaciones polimórficas

public interface Cosa

@Entity

public class Beca implements Cosa

@Entity

public class Pago implements Cosa

@Any(metaColumn = @Column(name = "tipo_de_cosa"))

@AnyMetaDef(idType = "long", metaType = "string", metaValues = {

@MetaValue(value = "Beca", targetEntity = Beca.class),

@MetaValue(value = "Pago", targetEntity = Pago.class) })

@JoinColumn(name = "tipo_de_cosa_id")

public Cosa getCosa() {

Mapeos 'complejos'

Mapeos 'complejos'

• @SecondaryTables + @SecondaryTable + @PrimaryKeyJoinColumn

• @Parent

• @Target

• @NotFound

Batch Processing

Batch Processing

• ¿Qué pasa si lanzamos esto?

Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {

Petition petition = new Petition(.....);

session.save(petition);

}

tx.commit();

session.close();

Batch Processing

• Hibernate se queda sin memoria.

• Podemos arreglarlo, haciendo operaciones en batch:o Activando hibernate.jdbc.batch_size (en persistence/hibernate.cfg.xml) y

poniendolo a un valor entre 10-50

Batch Processing

Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {

Petition petition = new Petition(.....);

session.save(petition);

if ( i % 20 == 0 ) { //el valor de la propiedad

session.flush();

session.clear();

}

}

tx.commit();

session.close();

Batch Processing

• Stateless Sessiono Sin caché de primer nivelo Sin caché de segundo nivelo Sin dirty checking/write behindo Sin cascadeso Sin interceptoreso Similar a JDBC

• Scrollable• HQL

Batch Processing

• En estrategias de Fetch hay una adicional (cuarta)o @BatchSize, recupera sentencias en bloque.

• MUY interesante...o soluciona el problema de los N+1 fetches.

Servicios

Servicios

• Un sistema de extensión (similar a plugins) de Hibernate.o Desde Hibernate 4.0o Permite el registro de servicios/implementaciones alternativas para, por

ejemplo: TransactionFactory (transacciones) JtaPlatform (gestión de JTA) JndiService JdbcServices ConfigurationService ...

Transitividad (cascades)

Transitividad

• Cascades de JPA:o CascadeType.PERSIST: cascada de persistso CascadeType.MERGE: cascadas de mergeso CascadeType.REMOVE: cascade de eliminacioneso CascadeType.REFRESH: cascade de refresh (volver a leer una entidad de

BD)o CascadeType.DETACH: cascade de detach (desunir de sesión)o CascadeType.ALL: todos los de arriba

Transitividad

• Cascades de Hibernate (@Cascade):o save-update...o deleteo locko replicate (copiar un objeto, muy muy raro)o evicto delete-orphan

Transitividad

• Delete orphan es interesante:o Sólo aplica a oneToMany.o Cuando elimino un elemento hijo de la colección indico que quiero

eliminarlo de la BD porque se ha quedado huérfano.o orphanRemoval en @OneToMany.

No estoy haciendo esto: session.remove() padre.geHijos().remove(0)

o No cuenta para Cascade.ALL.o @OneToMany(orphanRemoval = true)

• Probadlo!

Transitividad

• Recomendaciones de cascade:o Es más lógico en relaciones @OneToOne y @OneToMany (padre con

hijos)o Si el objeto hijo en un @OneToMany no tiene sentido sin el padre ->

Cascade.ALL y orphanRemovalo Típicos: persist, save-update...

Caching

Caching

• Caché de primer nivelo get() y load() me recuperan objetos que tienen en la sesión...

• Caché de segundo nivel

• Caché de querieso Hibernate tiene en cuenta cambios en los objetos que se muestran en las

consultas.o Depende del patrón de uso de la aplicación.

Caching

• Caché de segundo nivel:o Muy común, Hibernate se integra muy bien con varios proveedores de

caché.

o Típico para tablas de referencia (provincia, localidad, datos maestros...)

o Marcar entidades interesadas (o colecciones): @Cacheable

o @Cache(usage = CacheConcurrencyStrategy.TIPO_DE_CACHING)

Caching

• Tipos de Caching:o NONEo READ_ONLY: no se modifican a menudo...o NONSTRICT_READ_WRITE: pocas transacciones apuntando al mismo

item...o READ_WRITE: actualizaciones frecuentes.o TRANSACTIONAL

Caching

• Típicos proveedores:o EHCache: soporta todos los tipos de cachingo Infinispan: read-only, transactional

Caching

• Queries:o Activar use_query_cacheo Establecer el tiempo de timeouto Establecer las queries que quieres cachear

setCacheable(true)

Performance

Performance

• Hibernate no es lento.

• Recomendaciones de rendimiento:o Tener en cuenta las 4 estrategias de fetching (Select, Subselect, Join,

BatchSize)o Cuidado con N+1o Fetch-profiles (para personalizar escenarios de búsqueda)o Personalizar Fetch en Criterias

(criteria.setFetchMode("propiedad",MODO)) EAGER=JOIN, LAZY=SELECT Probadlo!"

Performance

• Tres grandes tipos de colecciones:o indexed collections (mapas, listas, arrays)o setso bags

• Las dos primeras son las más eficientes en save/remove/update de elementos.

• Bags y lists son más eficientes en @OneToMany con mappedBy

Performance

• One-shot-deleteo Imaginemos que tenemos 20 elementos, eliminamos 18 y añadimos 3o Podemos borrar 18 elementos (1 a 1) e insertar 3o Eliminar todo e insertar 5

En este caso conviene hacer clear();

• Probadlo!

Performance

• Marcar claves naturales @NaturalId (puede mejorar rendimiento al acceder a ellas)

• Realizar mapeos sencillos (los que hemos visto)

Performance

• Si realiza muchas consultas:o plantear estrategias estilo JOIN/SUBSELECTo Activar batch o utilizar @BatchSizeo Activar caché de segundo nivelo HQLo SQLo Query cache

Performance

• Si realiza una consulta muy pesada:o Eliminar cruces JOIN (empezando por colecciones)o Poner asociaciones *ToOne a Lazy (con Select o Subselect)o Índiceso HQLo SQLo Query cache

Validaciones

Validaciones

• Hibernate se complementa con Hibernate Validator

• Es la base de Bean Validation, un estándar Java EE 6o @NotNull

o @Past

o @Size

o @Pattern

o @Max

o @Email

o @CreditCardNumber

Validaciones

• Incluid las librerías de validation (es más sencillo en Java EE)o Añadid una anotación y probad a guardar.

• Podemos llamar a los validadores con:

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

Validator validator = factory.getValidator();

Set<ConstraintViolation<User>> constraintViolations =

validator.validate(user);

• Probadlo!

Envers

Envers

• Librería de auditoría.• Para activar la versión "básica" basta con:

o Copiar la libreríao @Auditedo Cuidado con relaciones: @NotAudited (de momento)

• Probadlo!

Envers

• Puedo hacer queries específicas:

AuditQuery query = AuditReaderFactory.get(session)

.createQuery()

.forEntitiesAtRevision(MyEntity.class, revisionNumber);

query.uni../getResu..()

• Probadlo!

Envers

• Dos estrategias, start y start-end

• Puedo guardar el usuario o información adicional

• Las querys pueden llegar a ser complejas:

List personsAtAddress = getAuditReader().createQuery()

.forEntitiesAtRevision(Person.class, 12)

.addOrder(AuditEntity.property("surname").desc())

.add(AuditEntity.relatedId("address").eq(addressId))

.setFirstResult(4)

.setMaxResults(2)

.getResultList();

Envers

• Puedo preguntar a una entidad por las revisiones que ha tenido

Number revision = (Number) getAuditReader().createQuery()

.forRevisionsOfEntity(MyEntity.class, false, true)

.setProjection(AuditEntity.revisionNumber().min())

.add(AuditEntity.id().eq(entityId))

.add(AuditEntity.revisionNumber().gt(42))

.getSingleResult();

• Probadlo!

Envers

• Envers es más quisquilloso en algún tipo concreto de mapeos:o Bagso @OneToMany+@JoinColumn, mappedBy (necesita @AuditJoinTable)o @OneToMany+@JoinColumn, insertable=false, updatable = false

(necesita @AuditMappedBy)

• Siempre se puede decidir no auditar una relación con @NotAudited.

Multi-tenancy

Multi-tenancy

• Una aplicación que sirve múltiples clientes.

• Típico de SaaS (Software as Service: google docs)

• Cada cliente sólo debe poder ver sus datoso Base de datos diferente, JDBC que cambiao Esquema separado, schema que cambia al conectarseo Única base de datos, discriminador

Multi-tenancy

• En Hibernate:Session session = sessionFactory.withOptions()

.tenantIdentifier( yourTenantIdentifier )

.openSession();

• Opciones de identificador:o DATABASEo SCHEMAo DISCRIMINATOR (No soportada aún, Hibernate 5)

¿Qué más es Hibernate?

¿ Qué más es Hibernate?

¿Qué más es Hibernate?

• Core• Shards: fragmentación horizontal• Search: búsqueda de texto completo (Lucene)• Tools• Validator: validación de datos• Metamodel Generator• OGM• Annotations• Entity Manager: operaciones y ciclo JPA• Envers: versionado e histórico

Recomendaciones y errores habituales

Recomendaciones

• No utilices claves compuestaso Claves surrogadas siempre, ni naturales ni compuestas

• En el import.sql (ficheros sql que carga Hibernate directamente), los ids, negativos (para no hacer conflicto con ids generados)

• No uses herencia, usa agregación (GoF)

• No uses mapas, usa entidades y relaciones

Recomendaciones

• Cuando estés mapeando por primera vez, hacer tests (incluso vacíos) está bien:o No arrancas el servidor de aplicaciones!

• Ojo con los "lazos" en los modelos y las relaciones bidireccionales...

• Se puede implementar SoftDelete (@SQLDelete) o restricciones globales de búsqueda (@Where)

• Puedo ver los valores de las consultas (?) -> en log4j, org.hibernate.type a TRACE.

Errores típicos

• Lazy Initialization Exception, causado por:o Intentar cargar desde la vista/lógica con la sesión cerrada una lista de

objetos/objeto con fetch a LAZY.o -> Hibernate.initialize()o -> Activar lazy load sin transacciones:

hibernate.enable_lazy_load_no_transo -> OpenSessionInViewo -> Conversaciones

Errores típicos

• Detached entity passed to persist, causado por:o Fijar un id manualmente a una entidad que utiliza un auto-generadoo Sin cascadas, intentar guardar una relación de un objeto que no está en la

base de datos.o Llamada persist() o save() de un objeto que ya está en la BD

• Cannot Open Connection, causado por:o Malos valores de conexión a la BD.

Errores típicos

• NPE en IntegerType.next(IntegerType.java:82), causado por:o Número de versión (@version) nulo

• Collection was not processed by flush, causado por (varios motivos, peliagudo):o Envers, bags y malas anotaciones de envers.o Jugar con las listas (utilizar add() a veces y sustituir las listas enteras al

mismo tiempo).• Llamo a persist() y no tengo id, causado por:

o persist() no asigna el id directamenteo -> usa save()

Errores típicos

• No row with the given identifier exists (uff), causado por:o Hay una entidad que apunta a una fila de la BD que ya no existeo Modificaciones en paralelo de la coleccióno Cascades delete/eliminaciones de elementos de la colección sin

actualizar el otro lado de la relación.

• Hibernate me devuelve datos duplicados• Relaciones bidireccionales mal mapeadas• Cruces cartesianos sin Distinct.ROOT_ENTITY

Errores típicos

• A collection with cascade delete-orphan was no longer referenced...o Mala gestión de las colecciones:Coleccion coleccion = miEntidad.getColeccion();

Coleccion coleccionNueva = new ColeccionImpl(coleccion);

miEntidad.setColeccion(coleccionNueva);

o -> add()• De principiante (y no tanto): constructor, @Entity, @Id...

Recapitulando...

Recapitulando...

• ¿Cómo es una clase persistente, una entidad?o @Entity y @Id (Constructor [Serializable])

• ¿Cómo se especifica los metadatos de mapeos?o Anotaciones | XML @OneToMany...

• ¿Qué relación hay entre identidad de objetos y de base de datos?o Dentro de una sesión, son lo mismo. Si hay objetos detached -> no.

• ¿Qué tipos de herencia hay?o 4 -> tablas única, 2 tablas (2), 3 tablas

• ¿Cuál es el ciclo de vida de un objeto persistente?o Persistent -> Detached. Transient nuevo, Delete a eliminar

Recapitulando...

• ¿Cómo se busca y ordena?o Criteria, HQL, SQL, anotaciones...

• ¿Cómo se recuperan objetos con asociaciones?o @OneToMany... fetches

Recapitulando...

• Preguntas de exameno get() y load() -> Hibernate | JPA (lazy)o save() / persist() / saveOrUpdate() -> = que antes, diferencias en

tratamiento en id.o named SQL Query? -> query definida para reusar. o SessionFactory? -> objeto único.. thread safe me da sesioneso Session? Threadsafe? -> no...o sorted/ordered collections? -> ordenada en memoria o no

Recapitulando...

• Preguntas de exameno transient/persistent/detached? -> estados de la entidado session.lock()? -> marcar entidad buena, bloquear BDo second level cache? ->o Constructor sin argumentos? -> no sabe qué crear...o Hibernate Entity Class Final? -> es malo por rendimientoo lazy initialization exception? -> o N+1 selects? ->

Conclusiones

Ventajas e inconvenientes de los ORMs

• Ideas?o Te olvidas de la base de datos (buscar inserts o updates modificados)o Y del SGBD (usando estándar SQL)o Simplifica la gestión de inserciones/actualizacioneso Otra herramienta/capa máso 'Mapeos complejos'o Conflictiva si no la usas bieno ...

Ventajas de los ORMs

• Diseño Orientado al Objeto puro (con pegas)• Separación de lógica y datos → Java EE, EJBs...• Productividad

o Operaciones en cascadao Navegacióno Mapea una vez → CRUD completo

• Separación de responsabilidades• Valor añadido (validación, envers...)

Inconvenientes de los ORMs

• Necesitas conocimientos de SQL• Conviene “olvidarse del modelo” → modelo relacional “incorrecto”.• Se delega el control de las consultas• Modelo de dominio anémico

o Exposición de la implementacióno Separación de lógica y datoso …

• … “(…) the main thing is to be practical and stop paying too much attention to lame patterns talk.”

Hibernate / JPA

Recommended