El Lenguaje Java nos permite crear aplicaciones que accedan a base de datos usando un protocolo en la forma de una API: la API JDBC. Una de las metas de JDBC era la de aislar el código de la aplicación de las diferentes implementaciones de manejadores de base de datos, permitiendo sustituir un manejador de bases de datos por otro sin modificar una línea de código. Desafortunadamente JDBC no proporciona una completa independencia de los manejadores de bases de datos ya que hay ciertas diferencias entre esas implementaciones que la JDBC no puede manejar y que nos obliga a hacer modificaciones en la aplicación si se cambia de un manejador de base de datos a otro.
Desajuste de Impedancias (Impedance Mismatch)
Se refiere a la diferencia de paradigmas existentes entre el modelo orientado a objetos y el modelo relacional
En el modelo del dominio, que es el que usamos en el diseño de nuestra aplicación, tenemos clases, las bases de datos tienen tablas. Otro de los problemas de JDBC es el trabajo que debe hacer el programador para convertir un objeto a un renglón de una tabla y viceversa. Esa dificultad en la traducción entre una clase y una tabla se debe a las diferencias entre ambos modelos.
Más detallada sería:
La API de Persistencia de Java, JPA (Java Persistence API)
Más conocida por sus siglas JPA, es la API de persistencia desarrollada para la plataforma Java EE. Es un Framework del lenguaje de programación Java que maneja datos relacionales en aplicaciones usando la plataforma Java en sus ediciones Standard (Java SE) y Enterprise (Java EE).
Nota: Interfaz de programación de aplicaciones (IPA) o API (del inglés Application Programming Interface) es el conjunto de funciones y procedimientos (o métodos, en la programación orientada a objetos) que ofrece cierta biblioteca para ser utilizado por otro software como una capa de abstracción. Son usadas generalmente en las bibliotecas.
Para entender JPA, tendremos que tener claro el concepto “persistencia”
Se entiende por persistencia como la acción de preservar la información de un objeto de forma permanente (almacenar), pero a su vez también se refiere a poder recuperar la información del mismo (leer) para que pueda ser nuevamente utilizada. En el caso de persistencia de objetos la información que persiste en la mayoría de los casos son los valores que contienen los atributos en ese momento, no necesariamente la funcionalidad que proveen sus métodos.
Nota: la persistencia no es ninguna capacidad, ni una propiedad de la POO, no tiene nada que ver con el paradigma en sí, sólo es el mecanismo que se usa para persistir información de un determinado tipo (como puede ser serializar, guardar datos en una tabla, en un archivo plano, etc).
En resumen la persistencia nos permitirá almacenar, transferir y recuperar el estado de los objetos. Para esto existen varias técnicas como lo son la serialización, los motores de persistencia, las bases de datos orientados a objetos entre otros, en nuestro caso utilizaremos JPA.
Resumiendo JPA es una abstracción que se ubica por encima de la capa JDBC y que le permite ser independiente de SQL, lo que busca reducirle al programador de la tarea de conversión entre el mundo de OO y el mundo relacional proveyendo de los siguientes servicios:
Realiza el Mapeo Objeto – Relacional (ORM), esto es establece cómo persistir los objetos en una base de datos.
Nota: El Mapeo Objeto-Relacional (ORM), es una técnica de programación para convertir datos entre el sistema de tipos utilizado en un lenguaje de programación orientado a objetos y la utilización de una base de datos relacional, utilizando un motor de persistencia. En la práctica esto crea una base de datos orientada a objetos virtual, sobre la base de datos relacional. Esto posibilita el uso de las características propias de la orientación a objetos (básicamente herencia y polimorfismo).
EntityManager (Api Administradora de entidad): ejecuta operaciones CRUD (Create, Read, Update, Delete) en la base de datos relacionales. Persiste los objetos a la base de datos. Definida en el paquete javax.persistence.
Permite la búsqueda y recuperación de objetos de la base de datos mediante su propio Lenguaje de Consulta de Persistencia de Java o SQL el Java Persistence Query Language (JPQL) y el Java Transaccion API (JTA) transacción y mecanismos de bloqueo cuando accedemos a datos de modo concurrente.
El objetivo que persigue el diseño de esta API es no perder las ventajas de la orientación a objetos al interactuar con una base de datos (siguiendo el patrón de mapeo objeto-relacional) y permitir usar objetos regulares conocidos como POJOs
Nota: Un objeto POJO (Un POJO o Plain Old Java Object) es una instancia de una clase que no extiende ni implementa nada en especial. Por ejemplo, un Servlet tiene que extender de HttpServlet y sobrescribir sus métodos, por lo tanto no es un POJO. En cambio, si se define una clase ‘Persona’, con sus atributos privados y sus correspondientes getters y setters públicos, una instancia de esta simple clase es un objeto POJO.
Published octubre 20, 2008 Java , Programacion 59 Comments
Vamos a programar un poco…
Antes cuando tenia que hacer una consulta en la base de datos, empleaba JDBC a “pelo” o Frameworks como iBatis e Hibernate. Eran APIs que permiten mapear una clase Java (Bean) con una tabla de la base de datos y facilitan mucho el trabajar con la persistencia de los objetos (usando metodos del estilo a “select”, “insert”, “update” y “delete”).
Pero ahora he conocido JPA y me parece que a partir de ahora sera lo unico que utilizare. Con JPA puedes hacer cosas como estas:
– Escribir el codigo de tu clase, y aunque no exista la tabla correspondiente en la base de datos, no importa!!. JPA se encargara de crear la tabla del modelo de datos. Esto esta Genial!!!, es decir, tu solo escribes el codigo y JPA con su mecanismo de persistencia ya se encargara de crear la tablas, si no existen y si existen pues las usa. Ademas da igual la base de datos, podrias por ejemplo escribir la aplicacion en MySQL y despues con un ligero cambio llevartela a Oracle.
– Sincronizacion. Viene tu jefe de proyecto y te dice, quiero que añadas dos columnas nuevas a esta tabla y elimines el campo primario de esta otra tabla. Y ya empiezas a sudar. Llevas escritas mas de 20 sentencias SQL y te toca cambiarlas. Eso se acabo. Es tan sencillo como irte al codigo de tu bean, y añadir 2 atributos nuevos que se mapearan como campos nuevos de la tabla. Chachi.
– Puedes tambien mantener la persistencia no necesariamente atacando a una base de datos, tal vez te interesaria persistir un objeto a un fichero de texto plano o XML.
Como ejemplo de uso de JPA vamos a implementar un pequeño sistema CMSpersonal. La idea es escribir una pequeña aplicacion que nos permita almacenar nuestros documentos en la base de datos. Y al decir “almacenar” me refiero a almacenar el contenido del documento en la propia base de datos, no su pathname o ruta en el disco duro. De esta manera aprovecharemos para ver como con JPA se hace tambien muy simple la insercion en campos BLOB de la base de datos, algo que muchas veces trae de cabeza a los desarrolladores de Java.
Este ejemplo de CMS (cuyo codigo dejo al final del articulo) sera muy simple. He preferido que el ejemplo no se complique con restricciones o constraints de la base de datos, asi que no existen tampoco claves foraneas a otras tablas. De manera que sera dificil que nos de un error, cuando intentemos insertar algun contenido. Tambien en esta primera version solo os dejare una aplicacion en modo consola (un interprete de comandos) que nos permitira ir insertando o consultando los documentos de nuestra base de datos. En otro articulo posterior, veremos como crear un interface grafico via web que nos permita manipular los documentos.
¿Que necesitamos?
– Pues un editor de Java. Puedes usar el que mas rabia te de. Eclipse, Netbeans u otro. Yo esta vez he usado Netbeans, para ir variando.
– Una base de datos. El ejemplo esta preparado para MySQL pero funcionara con ligeros cambios en Oracle u otra base de datos relacional. A su vez, no te olvides de incluir el driver JDBC de conexion a la base de datos en el Classpath.
– y por ultimo y lo mas importante, para trabajar con JPA necesitamos una implementacion de JPA. Existen muchos fabricantes que han hecho la suya (verimplementaciones). En el ejemplo yo he empleado EclipseLink, asi que basicamente, descargate esta implementacion, descomprimela y copia los siguientes .jar en el classpath de tu proyecto:
- eclipselink.jar
- javax.persistence_1.0.0.jar
En Netbeans podemos por ejemplo crear una Libreria con esos jar, que luego incluiremos en el proyecto, en Eclipse, pues bastaria con añadirlos al classpath.
Ya tenemos todo lo que necesitamos para trabajar, pero no esta de mas que te bajes la siguiente tarjeta de referencia de JPA.
Y ya puestos, la siguiente, que nunca esta de mas.
JPA trabaja fuertemente con anotaciones. Para mapear un bean (una clase java) con una tabla de la base de datos, tendriamos que escribir lo que se llama unEntity.
Esto es tan sencillo como escribir nuestro Bean, con sus atributos y metodos get y set. Y despues añadirle la anotacion “@Entity” a la par que seleccionamos uno de sus atributos como clave primaria con “@Id”. Por ejemplo, el siguiente trozo de codigo podria ser un Entity, que nos permitiria luego almacenar, recuperar, o actualizar campos sobre una tabla “usuario”:
@Entity
public class Usuario
{
@Id
private String id;
private String name;
private String email;
}
Con solo esto ya tenemos creada una “entidad” llamada “Usuario” y podriamos insertar, actualizar o eliminar entradas en una tabla llamada “Usuario” aunque esta aun no existe, siquiera. A que mola!!
Un fichero muy importante que tenemos que crear a parte de las clases “Entity” es el fichero “persistence.xml”, en este fichero vamos a indicar precisamente que clases son Entity, sobre que base de datos vamos a atacar, y cual es la politica de creacion de esta base de datos.
Este fichero “persistence.xml” debe colgar de un directorio “META-INF” que este accesible en el CLASSPATH. Esto es, si tu codigo por ejemplo lo estas dejando en la carpeta “src”, tendras que crear una carpeta “src/META-INF” y ahi dentro crear el fichero “persistence.xml”.
El contenido de este fichero es similar al que puedes ver en la siguiente imagen:
Fijate en el XML un momento:
– Tiene un nombre “DOCSPU” en el tag , este es importante, pues luego es por ese nombre por el que podremos acceder a este recurso o unidad de persistencia. Aqui se llama “DOCSPU” pero puedes darle el nombre o alias que quieras.
– Entre y vamos añadiendo todas las clases Entity que queremos manipular. Esto tambien es muy importante, porque si creas un Entity pero no lo añades a esta seccion del XML, para JPA no existe.
– Y por ultimo estan los properties. En estos properties estamos definiendo el mecanismo de conexion a la base de datos. Cambiando estos valores por los adecuados podemos conectar a cualquiera otra base de datos que tengamos.
– Existe una ultima propiedad que conviene tener activa en los primeros momentos, cuando estamos desarrollando:
Esta propiedad hace que si el modelo de datos no existe se cree de manera automatica, pero cada vez que invocamos al mecanismo de persistencia, borra el contenido de las tablas y las vuelve a crear si no existen previamente. Esto al comienzo cuando estamos de “pruebas” viene de fabula, despues ya podemos comentar esta opcion para trabajar con datos reales que tengamos insertados.
Tenemos los Entity ya creados. Como puedo por ejemplo, insertar uno de ellos en la base de datos.
Pues con un trozo de codigo similar al siguiente:
– Primero creamos un EntityManager que nos permita manipular y trabajar con los objeto Entity:
String UNIDAD_DE_PERSISTENCIA = "DOCSPU";
EntityManagerFactory factory = Persistence.createEntityManagerFactory(UNIDAD_DE_PERSISTENCIA, System.getProperties());
em = factory.createEntityManager();
Como ves, el nombre que uso es “DOCSPU”, esto es porque asi lo tenemos definido en el fichero “persistence.xml”, asi sabe como recuperar las clases y propiedades que corresponden a esta unidad de persistencia. Si tu cambiaste el nombre en el XML, aqui deberias poner el que hayas usado.
Una vez creada la EntityManager, ya es muy simple, abrir una transaccion e incluso almacenar elementos (Entity) en la base de datos. Un ejemplo para insertar un “Usuario” podria ser:
em.getTransaction().begin();
Usuario u = new Usuario();
u.setId(100);
u.setName("jose");
u.setEmail("notengo@gmail.com");
em.persist(u);
em.flush();
em.getTransaction().commit();
Como observas, hemos recuperado una transaccion (getTransaction), instanciado un objeto usuario, asignado valores a sus atributos, lo hemos “persistido” (almacenado) en la base de datos con “persist” y por ultimo un commit de la transaccion.
Es decir, solo escribiendo una clase, y un XML, ya hemos insertado un usuario con campos nombre y email en una tabla “Usuarios” que se ha generado de manera dinamica. ¿No te parece ideal?.
No hay que escribir metodos, insert, update ni delete, ni crear el modelo de la tabla si no nos interesa. Todo se hace dinamicamente.
Consultas:
Para hacer las consultas en JPA se emplea un lenguaje denominado JPQL, no es SQL exactamente porque trabaja con “objetos” no con “columnas” pero si muy parecido.
Por ejemplo, si la consulta de todos los campos de una tabla es “SELECT * FROM USUARIOS”, en JPQL la consulta seria “SELECT u FROM Usuario u”, Donde “Usuario” no es el nombre de una tabla, sino de la clase “Entity” y “u” son los identificadores del objeto.
Mas ejemplos: “SELECT u.id,u.name FROM Usuario u where u.name LIKE := PARAMETRO”.
Es muy parecido a construir un PreparedStatement donde pasamos los parametros.
Para ejecutar estas consultas empleamos el objeto “Query”. Query admite dos metodos:
– getResultList, cuando el conjunto de valores devuelto es una lista de valores, por ejemplo un SELECT de varios campos.
– getSingleResult, cuando solo se devuelve un unico objeto (fila).
Por ejemplo para obtener Todos los proyectos de una tabla “Proyectos”:
Query q = em.createQuery("SELECT p FROM MdcoreProject p");
List<MdcoreProject> proyectos = q.getResultList();
int num_proyectos = proyectos.size();
Si quisieramos ejecutar consultas con parametros, las variables a sustituir van precedidas de “:” y debemos pasarlas con setParameter. Ejemplo: una consultas de proyecto cuyo proyecto es “666” seria:
Query q = em.createQuery("SELECT p FROM MdcoreProject p WHERE p.id : = PROYECTO_ID");
q.setParameter("PROYECTO_ID","666");
MdcoreProject mi_proyecto_buscado = (MdcoreProject) q.getSingleResult();
Como veis, estamos trabajando con “objetos” no con clausulas SQL.
¿Y tenemos que tener esas consultas JPQL embebidas en el codigo?
Pues aqui tenemos otra ventaja de JPA, Si no queremos, no tenemos porque. Podemos si queremos definir “anotaciones” con las sentencias SQL en el cuerpo del “Entity”, estas sentencias SQL se indicarian con la anotacion “@NamedQuery”. Un ejemplo:
Fijate en el codigo del Entity, es una clase llamada “MdcoreUser” que implementa los datos de un usuario. Con @Entity ya indicamos que es una entidad. con @Table ya forzamos a que se mapee con una tabla llamada “MDCORE_USER”, en caso de no usar la anotacion @Table, el nombre de la tabla creada se llama exactamente igual al nombre de la clase java.
Con la anotacion @NamedQueries vamos indicando las diferentes sentencias SQL que queremos utilizar, bueno, perdon… sentencias JPQL. Y esto es “fantastico” otra vez, pues al ser anotaciones, podemos cambiarlas sobre “la marcha”. Aqui aprovecho y comento otras anotaciones de las que no habia hablado, ya vimos que con @Id vamos indicando que columnas son clave. Pues bien con @GeneratedValue podemos indicar si queremos que los campos clave se creen de manera automatica, por ejemplo mediante el uso de secuencias. En otro caso, somos nosotros los que debemos calcular el valor de un nuevo id cuando vayamos a insertar. Otra anotacion es @Column nos permite asociar un atributo a un nombre de columna en particular. Por ejemplo tenemos un atributo llamado “fxCreacion” pero en la base de datos la columna se llama “FECHA_CREACION”. En caso de no indicarlo, las columnas de la tabla se llamaran igual que el nombre del atributo del Entity.
En el caso de que queramos usar las anotaciones @NamedQuery, si que cambia un poco la forma de invocar a “Query” que vimos un poco mas arriba. y es que en este caso, en lugar de usar un createQuery(“String con el JPSQL”), debemos usar createNativeQuery(“nombre_de_la_anotacion_namedQuery_definida_en_el_Entity”).
Por ejemplo si tuvieramos:
@NamedQuery(name = "MdcoreUser.findById", query = "SELECT s FROM MdcoreUser " +
"s WHERE s.id = :id")
La consulta podria ser:
Query q = em.createNativeQuery("MdcoreUser.findByID");
q.setParameteR("id","100");
MdcoreUser u = q.getSingleResult();
En este punto tambien comentar que en estos entornos de desarrollo (Eclipse, netbeans) puede hacerse el paso inverso, es decir, a partir de una base de datos, generar el Entity correspondiente. A este proceso se le llama “Ingenieria inversa”. Pero no lo cubriremos en este articulo.
Podeis de todas formas obtener mas informacion en el sitio de Eclipse o enNetbeans. De todas formas, pienso que lo mas comodo es escribirlo uno mismo (ademas el Entity es un simple bean).
Ejemplo CMS:
Como se que esto al principio es complicado, aunque luego se le pilla el truco. Os dejo unos cuantos ficheros fuente con un ejemplo de aplicacion JPA. Solo incluyo los fuentes, para que no pese mucho, los .jar correspondientes a EclipseLink y driver JDBC debeis colgarlos vosotros.
Esta pequeña aplicacion es un interprete de comandos que nos permite insertar documentos en la base de datos en base a tags, por ejemplo podriamos insertar un documento “Introduccion a JPA.pdf” bajo los tags “Programacion,Java,JPA”. Consultar documentos en base a su tag (p.ej devolver todos los documentos almacenados que sean de la categoria: “Oracle”) y descargar documentos.
Usa varias tablas, pero la mas importante es MdcoreDocs. Realmente las demas son solo para un desarrollo a mayor nivel. Las tablas son:
- MdcoreUser, Guarda informacion de los usuarios
– MdcoreProject, Guarda informacion de los proyectos
– MdcoreMetadata, Guarda metadatos del proyecto (p.ej DOCUMENTOS, SCRIPTS…)
– MdcoreTags, Tags de los diferentes docs (Oracle, Java, Bases de datos, MySQL, etc..)
– MdcoreDocs, Los documentos almacenados en la base de datos.
– MdcoreSetDocTags, Permite asociar documentos con tags
Para simplificar no hay relaciones activas entre tablas, y por defecto cuando se inserta un documento en la base de datos, se asigna de manera automatica a un proyecto=0, usuario=1, metadato=1
(el proyecto 0 vendria a ser: DEFECTO).
El interprete de comandos se lanza con la clase MyDocs. Este seria por ejemplo una sesion donde almacenamos un documento en la base de datos:
Y aqui el resultado de insertar en la base de datos (nota que no he creado el modelo de datos, se crea de manera automatica):
Un Blob insertado en MySQL de la manera mas rapida y sencilla posible ^^
Este ha sido un tutorial muy basico, unicamente para que conozcais esta API y tal vez os sirva de ayuda para empezar a mapear vuestros Entity. no creo que siga con los tutoriales, pero con JPA se pueden hacer cosas mas complejas y establecer asociaciones 1 a 1 y 1 a M entre las tablas. Esperemos que Hermoso dia se anime y continue con algun tutorial mas avanzado. (Gracias Lechuck por enseñarme este API).
Los fuentes (estan como .pdf realmente son .tar, renombra de .pdf a .tar y descomprimelos, los subo asi, pq wordpress solo dejar subir pdfs e imagenes).
Enlace | Ejemplo de JPA, Codigo fuente
Enlace | Introduccion a JPA, Tutorial de Sun