Sie sind auf Seite 1von 225

Taller de Sistemas de

Informacin 2
Java Persistence API
El concepto de persistencia
En Java manipulamos objetos, los cuales son instancias de clases
Los objetos tienen referencias a otros objetos o a colecciones de los
mismos
En forma recursiva pueden referenciarse a si mismos
Los objetos encapsulan datos y comportamiento
El problema es que este estado es accesible solo mientras la JVM
esta ejecutando
Si la JVM se detiene o si el garbage collector destruye un objeto, este estado
desaparece
Algunos objetos necesitan que sus datos perduren la vida de la JVM
El concepto de persistencia
Un objeto que puede almacenar su estado en un medio permanente
y durable, se dice que es un objeto persistente
En las aplicaciones empresariales, el estado persistente suele
almacenarse en bases de datos relacionales
Existen diversos mecanismos para lograr este objetivo
Utilizar mecanismos manuales basados en JDBC
Realizar un mapeo automtico entre instancias de clases y tuplas de una base
de datos, a travs de un ORM
JPA es la especificacin de una solucin de ORM para la plataforma
Java EE
Entidades
Cuando decimos que un objeto se mapea en una tabla de una base
de datos relacional, se utiliza el termino ENTIDAD en lugar de OBJETO
Los objetos son instancias que solo viven en memoria
Las entidades son objetos que viven corto tiempo en memoria, pero
son persistentes en la base de datos
Entidades
Tienen la habilidad de ser mapeadas a la base de datos
Pueden ser concretas o abstractas
Soportan herencia y relaciones
Una vez que una entidad es mapeada a la base de datos, puede ser
gestionada por JPA
Podemos persistir, eliminar y consultar una entidad de la base de
datos
Entidades
En el mundo JPA, es un POJO
Tienen metadatos
Manejan estado, el cual puede ser accedido por getters y modificado
por setters
El estado de la entidad esta representado por los valores de los
atributos de la misma
OBJETO
ENTIDAD
Entidades
Estn anotadas con:
@javax.persistence.Entity
Debemos marcar un atributo como clave primaria, usando la
anotacin:
@javax.persistence.Id
Debe tener un constructor por defecto (publico o protected)
Debe ser una clase top-level (no puede interfaz o enumerado)
Entidades
La clase no puede estar marcada con final
Ningn mtodo o atributo de la clase puede estar marcado con final
Si la entidad debe ser pasada como parmetro a travs de una
interfaz remota, entonces debe implementar la interfaz
java.io.Serializable
Object-Relational Mapping
A travs del uso de metadatos (XML o anotaciones), JPA puede
mapear las entidades en la base de datos
Un proveedor de persistencia (implementacin de JPA) es el
encargado de usar estos metadatos para sincronizar el estado entre
los atributos de la entidad y la tabla
Proveedor de
persistencia
Manipulando entidades
Una vez que tenemos las entidades mapeadas, podemos utilizar JPA
para acceder a las entidades
Podemos consultar entidades y sus relaciones, SIN CONOCER la
estructura de la base subyacente
El elemento central de JPA que permite realizar esto, es el API:
javax.persistence.EntityManager
Manipulando entidades
El rol del EntityManager es
Gestionar entidades
Leer y escribir de una base de datos
Permitir operaciones CRUD simples
Permitir consultar complejas usando JPQL
Es una interfaz cuya implementacin la brinda un proveedor de
persistencia
Manipulando entidades
Por ejemplo, podemos usar el EntityManager de esta forma:
Manipulando entidades
Extendemos la entidad
Persistence Unit
Algo que nos falta en los cdigos anteriores es:
A que base de datos nos conectamos?
Como nos conectamos?
Cual es servidor, puerto y nombre de la base?
Con que usuario nos conectamos?
Que driver JDBC vamos a utilizar?
Esta informacin se encuentra en un elemento denominado
Persistence Unit
Persistence Unit
Cuando se crea el EntityManagerFactory, el nombre de la unidad de
persistencia se le pasa como parmetro
PERSISTENCE_CONTEXT_NAME
La informacin a utilizar para establecer la conexin, se coloca en el
archivo persistence.xml, en el classpath del modulo, dentro del
directorio META-INF
Ciclo de vida de una entidad
Bean Validation
Adems de la validacin manual (a travs de un Validator), es posible
utilizar Bean Validation automticamente en una entidad JPA
Las constraints pueden ser aplicadas en clases de entidad, clases
embeddable y mapped superclases
La validacin ocurre automticamente siempre luego de los eventos
PrePersist
PreUpdate
PreRemove
ORM
Para establecer el vinculo entre las entidades en el mundo Java y los
elementos a nivel relacional, debemos definir las anotaciones de
ORM para la entidad
JPA utiliza configuracin por excepcin
A menos que especifiquemos lo contrario, se asumen valores por
defecto
En ciertas situaciones, esto no nos sirve (ej. acceder a un esquema
legado)
@Table
Por defecto el nombre de la tabla y la entidad coinciden
Para configurar esto, debemos usar la anotacin
@javax.persistence.Table
El elemento mas bsico que podemos cambiar es el nombre de la
tabla
@Table(name = "t_book")
Podemos especificar el schema y el catalog de la tabla
@SecondaryTable
Permite colocar los datos de una entidad, en una tabla y N tablas
secundarias subordinadas
Podemos especificar una @SecondaryTable o un conjunto de tablas,
usando @SecondaryTables
Para cada atributo, usando @Column, podemos especificar a que
tabla pertenece
@SecondaryTable
Debemos tener cuidado con este tipo de tablas y la performance
Cuando queremos acceder a los atributos de una entidad, vamos a
tener que realizar un join entre las tablas involucradas
Pueden ser una buena alternativa cuando tenemos atributos costosos
(BLOBs) que queremos aislar en tablas especificas
Primary Keys
Identifican unvocamente una tupla en una tabla en la base de datos
Puede ser una columna o un conjunto de columnas
JPA requiere que las entidades tengan un identificador mapeado a
una clave primaria
Una vez actualizado (en la base), el valor de una clave primaria no
puede ser actualizado
@Id / @GeneratedValue
@Id es utilizado para denotar un atributo simple que se mapea a la
clave primaria
Puede ser del siguiente tipo:
Primitivo: byte, int, short, long, char
Wrapper: Byte, Integer, Short, Long, Character
Arrays de primitivos/wrappers: int[], Integer[]
Strings, numeros y fechas: String, BigInteger, Date
@Id / @GeneratedValue
El valor de la clave primaria puede ser asignado en forma manual o
ser generado automticamente
Para esto usamos la anotacin @GeneratedValue, que puede tomar
cuatro valores posibles
SEQUENCE , IDENTITY, TABLE, AUTO
El valor por defecto es AUTO
Campos Identity
La base debe soportar columnas de tipo autogeneradas, como SQL
Server y MySQL
Debemos hacer
Tabla
Podemos generar los valores de clave primaria a travs de una tabla e
la propia base de datos
Esta tabla contendr una fila por cada entidad que necesite generar
valores de clave primaria
Podemos usar los valores por defecto o utilizar una tabla ya creada
Tabla
Para mapear a una tabla existente, usamos un TableGenerator
Tabla
La tabla generada en este caso se mapea a la siguiente estructura
Estrategia por defecto
Cuando especificamos que la estrategia es AUTO, estamos indicando
que el proveedor de persistencia puede seleccionar la estrategia que
crea conveniente
Generalmente la seleccin es TABLE, ya que es el mecanismo
garantizado para cualquier manejador de base de datos
En el caso de utilizar Hibernate como proveedor de persistencia, el
nombre de la tabla por defecto, es hibernate_sequences
Primary Keys compuestas
Cuando se mapean las entidades, es una buena practica:
Usar una nica columna como clave
Que esta columna sea de un tipo integral (INTEGER, LONG, etc.)
A veces esto no es posible
Si tengo que adherir la clave a ciertas reglas de negocio
Si tengo que mapear un esquema legado
Tenemos dos posibilidades, @EmbeddedId o @IdClass.
@Embedded
La anotacin @Embedded representa objetos que sern embebidos
dentro de otros objetos
Un objeto embebido no tiene identidad (no tiene PK por si mismo)
Sus atributos terminaran formando parte de las columnas de la tabla
que contiene el objeto embebido
@Embedded
Un objeto de este tipo debe:
Tener un constructor sin parmetros
Debe tener getters y setters para los atributos all presentes
Debe definir el mtodo equals y el mtodo hashCode
La clase no tiene una identificacin por si misma, esto es, no tiene atributos
marcados con @Id
@Embedded
@EmbeddedId
Esta anotacin se utiliza
cuando representamos los
campos de una clave
compuesta a travs de un
@Embedded
En este caso, no
necesitamos indicar la clave
primaria con @Id
@EmbeddedId
En este caso, la clave primaria no es un atributo simple, sino que esta
representada por una instancia del objeto embebido
Para utilizarla, debemos hacer:
@IdClass
Es parecido al mecanismo anterior, pero los atributos que componen
la clave primaria, deben especificarse en la clase utilizando @Id (por
separado)
@IdClass
Luego, en la clase indicamos cual es la clase que representa los
valores de clave primaria
Atributos
Componen el estado de la entidad
Entre otros, podemos mapear los siguientes tipos:
Primitivos y sus correspondientes wrappers
Arrays de bytes y chars
Strings, tipos numricos y tipos temporales
Tipos enumerados
Tipos que implementen Serializable
Colecciones de tipos bsicos y embeddables
Atributos
Una entidad tambin puede tener atributos
De tipo entidad
Colecciones de entidades
Clases embebidas
Estos tipos de atributos, requieren el uso de relaciones entre
entidades
Como con los nombres de tablas, se utiliza configuracin por
excepcin
@Basic
Es la anotacin mas simple para mapear un campo a la base de datos
Permite hace un override a la forma en como se levantan los datos de
la base
@Basic
optional
Permite indicar si el atributo puede o no ser nulo
No aplica para tipos de datos primitivos
fetch
Puede tomar dos valores: LAZY o EAGER
Le indica al provider cuando debe cargar el dato en cuestin
EAGER: Cuando se carga la entidad
LAZY: Cuando se accede al atributo
@Column
@Column
Un aspecto importante se da cuando tenemos un atributo con
Una validacin B.V. del tipo @NotNull
Un mapeo @Column con el atributo nullable en false
La primera aplica en el espacio de Java
La segunda aplica en el espacio de la base de datos
@Temporal
Los tipos de datos Date (java.sql y java.util) puede ser llevados a la
base a diferentes representaciones
Para controlar esto, usamos la anotacin @Temporal, que puede
tomar tres valores
DATE: Solo se almacena la fecha
TIME: Solo se almacena la hora
TIMESTAMP: Se almacena fecha y hora completa
@Transient
En JPA, cuando anotamos la clase con @Entity, esto hace que todos
sus campos formen parte del estado persistente
Si no queremos persistir un atributo de una entidad, podemos:
Colocarle la anotacin @Transient
Colocarle el modificador de acceso transient al atributo
@Enumerated
Los valores de un enumerado son constantes, que tienen implcito un
ordinal, el cual depende del orden en el que fueron declarados
En la base de datos, podemos almacenas la constante (como string) o
el ordinal del enumerado
@Enumerated
@Enumerated acepta dos posibles valores
EnumType.STRING para indicar que se quiere guardar el nombre de la
constante del valor del enumerado
EnumType.ORDINAL para indicar que se quiere guardar el ordinal del valor del
enumerado
ORDINAL es el valor por defecto
Embeddables
Tienen 2 partes
La clase que se embebe
La clase que embebe a la primera
En el primer caso se usa la anotacin @Embeddable para indicar que
es un objeto que puede ser embebido dentro de otro
En el segundo caso, se usa la anotacin @Embedded para indicar que
estamos colocando un objeto embebible all
Relaciones entre objetos
Representa un vinculo entre dos entidades
Tienen direccin
Puede ser unidireccionales o bidireccionales
Relaciones entre objetos
Tienen cardinalidad
Esto refiere a la cantidad de participantes en cada extremo de la relacin
Relaciones en la base
Pueden ser establecidas con columnas de join (foreign keys)
Relaciones en la base
O pueden ser establecidas por tablas de mapeo
Relaciones entre entidades
Relaciones entre entidades
Customer y Address tienen una relacin unidireccional
Relaciones entre entidades
Customer y Address tienen una relacin bidireccional
CUIDADO
Lo anterior, NO ES exactamente igual a esto
@OneToOne
En estos casos, se tiene una referencia a un elemento
@OneToOne
@JoinColumn
Es similar a @Column, solo que es utilizada para customizar la
columna de foreign key
Siempre debe utilizarse en el lado dueo de la relacin (el que no
contiene mappedBy)
En el caso anterior, no tenemos lado mappedBy, solamente uno,
debido a que es unidireccional
@OneToMany unidireccional
En este caso, el objeto origen mantiene una coleccin de objetos
destino
@OneToMany unidireccional
Este tipo de relaciones en JPA, generan una tabla intermedia de
mapeo entre ambas entidades
@JoinTable
Podemos usar esta anotacin para customizar la tabla de mapeo
entre ambas entidades
@JoinTable
La tabla obtenida, en este caso cambia a lo siguiente:
@OneToMany unidireccional
Para relaciones de este estilo, la accin por defecto es usar una tabla
de mapeo
Sin embargo, es posible modificar esto para utilizar una columna de
join en la tabla subordinada
Basta indicar en la entidad padre, que vamos a utilizar una
@JoinColumn en lugar de @JoinTable
@OneToMany unidireccional
En este caso, la tabla de mapeo queda de la siguiente forma:
@OneToMany bidireccional
Para transformar esta relacin en bidireccional, en realidad debemos
hacer que la lnea de la orden referencia a la orden
Para esto, agregamos una referencia a la orden y utilizamos la
anotacin @ManyToOne
Es importante en este caso, que la anotacin tenga el atributo
mappedBy para indicar que es la inversa de la anterior
@ManyToMany bidireccional
@ManyToMany bidireccional
Las tablas obtenidas en estos casos son las siguientes:
Fetching
Todas las anotaciones definen un mecanismo de fetching
(recuperacin de datos)
Los objetos asociados pueden ser cargados:
Inmediatamente: FetchType.EAGER
Cuando se requieran: FetchType.LAZY
Fetching
Por ejemplo, en esta situacin:

Ni bien levantemos el primer objeto (por ejemplo, buscando por ID),


vamos a levantar TODO lo relacionado
El impacto en performance es enorme
Fetching
En esta otra situacin:

Solo si hacemos esto:


class1.getClass2().getClass3().getClass4()
Entonces en ese momento se van a cargar los datos de las entidades
relacionadas
Fetching
Herencia
Es un concepto que a nivel relacional no tiene contraparte como en el
caso de las relaciones
El problema que tenemos es como mapear un modelo jerrquico
(Java) en un modelo plano (relacional)
JPA provee tres estrategias para resolver este problema (cada una con
ventajas y desventajas)
Herencia
single-table-per-class-hierarchy
Todos los atributos, de todas las entidades, se colocan en una nica tabla
Es la estrategia por defecto
joined-subclass
Cada entidad en la jerarqua, concreta o abstracta, es mapeada en su propia
tabla
table-per-concrete-class
Cada entidad concreta de la jerarqua, se mapea en una tabla
Es opcional en JPA 2.x (CUIDADO)
Single-Table-per-Class Hierarchy
La anotacin usada es
@Inheritance

Pero podemos omitir


completamente el uso de
anotaciones porque este
es el enfoque por defecto
Single-Table-per-Class Hierarchy
El problema con este tipo de tablas, es que generan tablas con
muchos huecos
Pero son muy buenas, porque no tenemos que hacer JOINs para
levantar los datos
Single-Table-per-Class Hierarchy
Como los datos de las diferentes entidades estn juntos, necesitamos
una forma de discriminarlos
Por esto, se agrega una columna nueva, el discriminador (DTYPE)
Por defecto es de tipo String, mapendose a un Varchar en la base
Podemos customizar esta con @DiscriminatorColumn
@DiscriminatorColumn
@DiscriminatorColumn
En este caso, los datos almacenados cambian a lo siguiente:
Joined-Subclass
Joined-Subclass
Joined-Subclass
Aun podemos usar el discriminador en las clases, para customizar e
indicar el tipo de entidad en la tabla de la clase raz
Este enfoque es el mas intuitivo, y el mas similar a una jerarqua Java
El problema que tiene, es la cantidad de JOINs requeridos para
recuperar los datos de una clase concreta
Table-per-Concrete-Class
Table-per-Concrete-Class
Table-per-Concrete-Class
En este enfoque, las tablas en las hojas, replican los atributos en
clases concretas mas arriba en la jerarqua
En JPA, por defecto se les coloca el mismo nombre
Pero puede suceder que un esquema legado utilice nombres
diferentes
Podemos hacer entonces un override de los atributos
Table-per-Concrete-Class
Tipos de entidades en jerarqua
Entidades abstractas
No siempre las entidades de las que se hereda tienen porque ser concretas
En este caso, el mapeo es como el de una entidad, la nica diferencia es que
la clase no se puede instanciar
Clases transient (no-entidades)
No generan informacin de mapeo, por lo tanto sus atributos no forman
parte del estado persistente
Gestionando los objetos
El EntityManager es la pieza central de JPA
Permite, dentro de un contexto de persistencia
Crear y remover entidades
Localizar entidades por clave primaria
Permite lockear el acceso a entidades (en forma pesimista u optimista)
Permite crear y ejecutar queries en JPQL o usando el API de Criteria
EntityManager
Mientras una entidad no entre en contacto con una instancia de un
EntityManager, se dice que NO esta siendo administrada
En cuanto entra en contacto (creacin, query, modificacin, etc.) ah
decimos que pasa al estado MANAGED
En este estado, el EntityManager se encargara de sincronizar
automticamente el estado con la base de datos
Obteniendo un EntityManager
Tenemos dos tipos de EntityManager
Application Managed EntityManager
Container Managed EntityManager
El primer caso se da cuando usamos el EntityManager fuera de un
servidor de aplicaciones
En el segundo, estamos dentro de un servidor, como WidlFly
Persistence Context
Es un conjunto de entidades administradas (managed), en un
momento dado y para una transaccin de un usuario dada
Solo una instancia de una entidad, con la misma identidad persistente
(PK) puede existir en un persistence context
Solo las entidades contenidas en un persistence context son
manejadas por el EntityManager
Persistence Context
El EntityManager actualiza o consulta el contexto de persistencia
cuando un mtodo del API de EntityManager es invocado
Por ejemplo:
Cuando se invoca el mtodo persist, la entidad pasada como
parmetro se agrega al contexto de persistencia, si no existe en el
mismo
Cuando se busca una entidad por ID, primero se verifica si no esta
cargada en el contexto de persistencia
Persistence Context
Por los motivos anteriores, el contexto de persistencia se denomina
tambin cache de primer nivel
Por defecto, los objetos viven en el contexto de persistencia, SOLO
MIENTRAS DURE LA TRANSACCION ACTUAL
Por ejemplo, si tenemos dos usuarios ejecutando en dos
transacciones diferentes
Persistence Unit
Es el archivo que permite configurar el contexto de persistencia
Viene dado por el archivo persistence.xml
Se encuentra en el META-INF dentro del classpath de la aplicacin
Permite establecer diferentes tipos de parmetros para configurar el
contexto de persistencia creado
Se pueden utilizar propiedades estndar y/o propiedades del
proveedor de persistencia (por ejemplo Hibernate)
Por ejemplo
Persistence Unit
Ejemplo
Las tablas asociadas al ejemplo anterior quedan de la siguiente forma:

Asumamos que em es una instancia de EntityManager y tx una


instancia de EntityManagerTransaction
Persistiendo una entidad
Si los datos no existen en la base, sern insertados
En caso contrario, se propaga una EntityExistsException
Buscando por ID
Dado el ID, usamos el mtodo find

Si la entidad existe, es devuelta


Si no existe, se retorna null
Buscando por ID
Otra forma alternativa, es usando el mtodo getReference, que
levanta los datos de la entidad en forma LAZY
Buscando por ID
En el caso de getReference, si la entidad no existe, se genera la
excepcin EntityNotFoundException
Los datos de la entidad se recuperan en forma LAZY, por lo que debe
hacerse esto DENTRO del contexto de persistencia
Si la entidad se vuelve detached, ya no podemos recuperar los datos,
generando una LazyInitializationException
Borrando una entidad
Utilizamos el mtodo remove
Al borrar una entidad, esta:
Se elimina de la base de datos
Se desvincula del persistence context
Pasa a estado detached
No puede volver a ser sincronizada
Sin embargo, el objeto aun es accesible desde Java (es un POJO
tradicional)
Sincronizacin con la base
El EntityManager tiene un cache de primer nivel, esperando a que la
transaccin se commitee, o que los datos sean flusheados a la base
Cuando realizamos mltiples operaciones con el contexto de
persistencia (persistir dos entidades por ejemplo) las sentencias se
hacen permanentes cuando se commitean los cambios
Flushing
El mtodo flush puede hacer que los datos sean enviados a la base,
pero aun no se commitee la transaccin
El problema que podemos tener al flushear manualmente, es que
podemos ejecutar sentencias que pueden violar una restriccin de
integridad
Por ejemplo
Refresh
Es usado para sincronizar datos, pero en la direccin opuesta al flush
Esta operacin sobre escribe el estado persistence de la entidad en el
cache de primer nivel
Es til para cuando queremos deshacer cambios que hicimos en
memoria
Refresh
Contains
El mtodo contains() retorna un booleano (true o false), indicando si
en el contexto de persistencia actual, una entidad esta siendo
administrada
Contains
Clear y Detach
El mtodo clear() limpia el contexto de persistencia
Todas las entidades managed pasan automticamente a estado
detached
El mtodo detach() recibe una entidad y la desconecta del contexto
de persistencia
Cualquier cambio que se haga sobre la misma no ser sincronizado
contra la base de datos
Clear y Detach
Merging
Para asociar una entidad que esta desconectada de un contexto de
persistencia, debemos re - attachearla (mergearla)
Es una situacin comn cuando:
Una entidad es devuelta por un componente de negocio a presentacin
Se le hacen cambios en presentacin
Es enviada al componente de negocio para ser actualizada en la base
Merging
Actualizacin de una entidad
Tenemos dos formas de hacerlo
La anterior, en la cual una entidad detached (con cambios en su estado), es
mergeada al persistence context actual
Pero si la entidad ya esta managed, los cambios se efectuaran
automticamente sin necesidad de mergear explcitamente
Cascading
Existen situaciones en las cuales las operaciones aplicadas sobre una
entidad, deben ser propagadas a las entidades relacionadas
Esto es lo que se denomina Cascade de eventos
Por ejemplo, si Customer y Address estan vinculados, podemos hacer
esto:
Cascading
En este caso, estamos explcitamente guardando ambos elementos
Cascading
Si usamos Cascade al persistir, obtenemos
Cascading Eventos
JPQL
Es un lenguaje de consulta usado para definir bsquedas contra las
entidades, independientemente del motor de base de datos utilizado
Es muy similar al SQL
En vez de tablas, usamos clases
En vez de columnas, usamos atributos
En vez de joins por FKs, usamos navegacin
JPQL
El ejemplo mas simple de consulta JPQL es:

SELECT b
FROM Book b

Book representa una entidad


b representa un alias utilizado en la consulta (en este caso, es similar
a * en SQL)
JPQL Forma general
Select
Permite seleccionar los resultados de la consulta
Permite devolver lo siguiente
Una entidad
Un atributo de una entidad
Una constructor expression (un New)
Una funcin de agregacin
Una expresin de navegacin (usando el .)
Select
La forma general es:

Por ejemplo, si Customer es una entidad, a la cual se le da el alias c,


entonces estos son unos ejemplos simples de seleccin:
Select
Desde JPA 2.0, se soporta en la seleccin el operador CASE-WHEN-
THEN-ELSE
Select
Si Customer tiene una relacin (a 1) con Address, entonces la
siguiente consulta retorna una lista de direcciones
Select
Si Address tiene una relacin con Country, el cual tiene un cdigo
(code), entonces podemos usar la navegacin con . para recuperar
ese valor
Select
Podemos usar un constructor en el select, creando nuevas instancias
de los elementos seleccionados
Select
Para remover duplicados, podemos usar el operador DISTINCT
Select
Podemos usar funciones de agregacin sobre los elementos del Select
Tenemos las operaciones de agregacin
AVG, COUNT, MAX, MIN, SUM
Los resultados pueden ser agrupados usando GROUP BY y ser
filtrados usando HAVING
Tenemos tambin funciones escalares que podemos usar en el
SELECT, en el WHERE y en el HAVING
Select
Sobre valores numricos:
ABS, SQRT, MOD, SIZE, INDEX
Sobre valores strings
CONCAT, SUBSTRING, TRIM, LOWER, UPPER, LENGTH, LOCATE
Sobre valores fecha
CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP
From
Define las entidades sobre las que vamos a buscar, utilizando
variables de identificacin
Una variable de identificacin es un alias
Permite utilizar dicho alias en los dems elementos de la consulta
(Select, Where)
Where
Es una expresin booleana usada para restringir el resultado de un
Select, un Update o un Delete
Where
Soporta los siguientes operadores
=, >, >=, <, <=, <>
[NOT] BETWEEN, [NOT] LIKE, [NOT] IN
IS [NOT] NULL, IS [NOT] EMPTY
[NOT] MEMBER [OF]
LIKE
Parmetros
JPQL soporta parmetros posicionales
Se especifican con un ?, seguido de la posicin (1, 2, )
Cuando se ejecuta la query, los parmetros deben ser reemplazados
Parmetros
Tambin soporta parmetros nombrados
Se especifican con un : seguido de un nombre lgico
Como en el caso anterior, al ejecutar se debe dar valor a los
parmetros
Subqueries
Es una query que puede ser embebida en un WHERE o en un HAVING
La evaluacin ocurre como parte de la evaluacin de la consulta
padre
Order by
Como en el caso de SQL, permite ordenar los valores devueltos
Group by / Having
Bulk Delete
Retorna la cantidad de tuplas eliminadas
Bulk Update
Tipos de queries
Dynamic Queries
Named Queries
Criteria API (Desde JPA 2.0)
Native Queries
Stored Procedure Queries (Desde JPA 2.1)
Recuperacin de resultados
Los mtodos mas usados son:
getResultList: Ejecuta y retorna una lista de resultados (entidades,
expresiones, atributos, etc.)
getSingleResult: Ejecuta y retorna un nico valor. Si existe mas de un
resultado, genera una excepcin NonUniqueResultException
Para ejecutar un update o delete, debemos usar el mtodo
executeUpdate
Este retorna siempre el numero de tuplas afectadas
Recuperacin de resultados
Para establecer los valores de los parmetros, debemos usar el
mtodo setParameter correspondiente
Podemos utilizar los mtodos setFirstResult y setMaxResults para
controlar el paginado de la consulta (si la base lo soporta)
Queries dinmicas
Son creadas cuando la aplicacin las necesita, utilizando el mtodo
EntityManager.createQuery()
Queries dinmicas
Si no conocemos la estructura de la consulta de antemano, podemos
usar concatenacin de strings para armarla
Esto puede presentar problemas de seguridad
Queries dinmicas
Podemos utilizar parmetros (nombrados o posicionales)
Queries dinmicas
Es importante tener en cuenta el costo de procesar estas consultas
por parte del provider de performance
Cada consulta de estas:
Debe ser procesada, no puede ser predecida
Debe parsearse el JPQL
Debe accederse a los metadatos
Debe generarse el SQL apropiado
Queries nombradas
Son estticas e incambiadas a nivel estructural
Aceptan parmetros
Son mas eficientes, porque el proveedor de persistencia puede
transformar las consultas en SQL cuando la aplicacin se inicia
Se usa la anotacin @NamedQuery
Generalmente se definen en la entidades asociadas
Queries nombradas
Queries nombradas
Queries nombradas
El nombre de la query nombrada, debe ser nico en el scope de
persistencia que se este utilizando
Por ejemplo, solo podemos tener una query de nombre findAll
Como podemos tener mltiples entidades que requieran un findAll,
podemos hacer:
Concurrencia
El problema de la concurrencia
Concurrencia
El ganador es el ultimo que commitea
No es un problema especifico de JPA
No es un problema nuevo, por lo que existen mltiples mecanismos
para resolverlo
Estos se reducen a 2
Optimistic Locking
Pessimistic Locking
Locking EntityManager / Query
LockModeType
OPTIMISTIC
Bloqueo optimista
OPTIMISTIC_FORCE_INCREMENT
Bloqueo optimista, forzando siempre el incremento del numero de versin
PESSIMISTIC_READ
Bloqueo pesimista, sin necesidad de volver a leer los datos de nuevo para obtener el lock
PESSIMISTIC_WRITE
Bloqueo pesimista, forzando la serializacin de las transacciones que quieran escribir la
entidad
PESSIMISTIC_FORCE_INCREMENT
Bloqueo pesimista, forzando el incremento del campo de versin
NONE
No se usa un mecanismo de locking
LockModeType
Versionado
Permite adjuntar un numero de versin a las entidades
La primera vez que se persiste una entidad, esta tendr el numero de
versin 1
Cuando se actualice la entidad y se commiten los cambios a la base, el
nmero se incrementar a 2, y as sucesivamente
Para esto, debemos colocar en la entidad un atributo para manipular
la versin
@Version
Podemos colocar esta
anotacin sobre un atributo
de tipo Integer, Short, Long o
Timestamp
@Version
La entidad puede acceder a su valor de versin, pero NO DEBE
modificarlo
Solo el proveedor de persistencia tiene permitido colocar un valor en
este campo o realizar actualizaciones sobre el mismo
Al usar este campo, si no se especifica un LockType, automticamente
se utiliza OPTIMISTIC_FORCE_INCREMENT
Por ejemplo
Locking optimista
Asume que las transacciones no presentan muchos conflictos entre si
Cuando una transaccin viola el bloqueo optimista, se genera una
excepcin de tipo OptimisticLockException
Como se genera?
Bloqueando la entidad con el LockModeType apropiado
Dejando que el provider chequee el atributo anotado con @Version
Locking optimista
Locking pesimista
En este caso, el lock es obtenido antes de realizar las modificaciones
sobre la entidad
Es restrictivo, generando degradacin de performance, sobre todo en
sistema con un alto nivel de concurrencia
La base de datos es la que provee el mecanismo de locking apropiado.
SELECT ... FOR UPDATE
Si se viola, se propaga PessimistickLockExcetion