Introducción a Java Persistence API

36,241 views
36,025 views

Published on

Introducción al trabajo con Java Persistence Api (JPA), conceptos básicos y ejemplo aplicado a una tabla posts con los siguientes campos: post_id, post_title, post_date, post_body utilizando netbeans

Published in: Education
1 Comment
11 Likes
Statistics
Notes
  • Muchas gracias José!! Me han sido de mucha utilidad tus publicaciones.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
36,241
On SlideShare
0
From Embeds
0
Number of Embeds
12
Actions
Shares
0
Downloads
1,116
Comments
1
Likes
11
Embeds 0
No embeds

No notes for slide

Introducción a Java Persistence API

  1. 1. Lo hemos logrado. Qué sigue? Ya hemos desarrollado una aplicación web con JAVA EE, utilizando Derby como base de datos, esta misma aplicación puede desarrollarse de diferentes maneras, las cuales no sólo resultan más eficientes sino más seguras
  2. 2. Alternativas <ul><li>Java Persistence
  3. 3. Java Server Faces CRUD
  4. 4. Spring MVC 2.5 </li></ul>
  5. 5. Java Persistence <ul><li>La API de Java Persistence (JPA) es un framework para el trabajo con bases de datos relacionales, compuesta por tres partes: </li><ul><li>El paquete: javax.persistence
  6. 6. El lenguaje de consultas de Persistence
  7. 7. Los metadatos para los objetos y sus relaciones </li></ul></ul>
  8. 8. Java Persistence: Definiciones <ul><li>Una entidad en JPA se refiere generalmente a una tabla de la base de datos
  9. 9. Las instancias de una entidad corresponden a filas dentro de la tabla
  10. 10. Generalmente las entidades se relacionan con otras entidades, estas relaciones se expresan mediante los metadatos
  11. 11. Los metadatos de las relaciones que se dan entre los objetos se pueden definir en un archivo XML o empleando anotaciones en el archivo de cada clase </li></ul>
  12. 12. Java Persistence: Definiciones <ul><li>El lenguaje de consultas JPQL recuerda en su forma al SQL estándar, pero en lugar de operar sobre tablas de la base de datos lo hace sobre entidades
  13. 13. POJO : Plain Old Java Object -> clases que no extienden a ninguna otra: MyDb.java es POJO, NewPostServlet no es POJO </li></ul>
  14. 14. Qué es Persistencia? <ul><li>Por persistencia se entiende almacenar los datos de una aplicación en un medio físico como una base de datos, un archivo de texto, etc... </li></ul>
  15. 15. Posts: tabla -> entidad <ul><li>La tabla Posts que empleamos en el ejemplo anterior será ahora una entidad.
  16. 16. Ahora que es una entidad cuenta con tres características: </li><ul><li>Persistencia: los datos pueden almacenarse y recuperarse de una base de datos
  17. 17. Identidad: cada instancia de la entidad es única
  18. 18. Soporte Transaccional: las operaciones CRUD (CReate, Update, Delete ) para esta entidad se realizan de forma transaccional </li></ul></ul>
  19. 19. Antes de comenzar a #programar public class post{ <ul><li>private int post_id;
  20. 20. private String post_title;
  21. 21. private Date post_date;
  22. 22. private String post_body;
  23. 23. //getter & setter methods </li></ul>}
  24. 24. Antes de comenzar a #programar <ul><li>Por getter & setter methods nos referimos acá a los métodos que sirven para fijar y recuperar valores, continuando con el mismo ejemplo anterior podríamos pensar por ejemplo en los siguientes: </li><ul><li>get_id
  25. 25. set_id
  26. 26. get_title
  27. 27. set_title </li></ul></ul>
  28. 28. Anotaciones (@) <ul><li>El siguiente cambio en el pseudocódigo convierte a esta clase POJO en una entidad: </li></ul><ul><ul><li>@Entity
  29. 29. public class posts{ </li><ul><li>private int post_id;
  30. 30. private String post_title;
  31. 31. ... </li></ul></ul></ul>
  32. 32. Identidad <ul><li>Ahora debemos incluir una nueva anotación que permita definir el campo que identificará cada instancia de la entidad que estamos definiendo: </li></ul>@Entity public class posts{ @Id private int post_id; private String post_title; private Date post_date; private String post_body; //getter and setter methods }
  33. 33. Convenciones <ul><li>Nombre de la tabla: MITABLA
  34. 34. Nombre de la clase: MiTabla
  35. 35. Nombre de las columnas: ATTR1, ATTR2, ATTR3
  36. 36. Nombre de los atributos: attr1, attr2, attr3 </li></ul>
  37. 37. @ Generando id's automáticamente <ul><li>Si queremos que los id's de nuestra entidad se generen de forma automática podemos incluir otra anotación: </li></ul>... @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private int post_id; ...
  38. 38. EntityManager <ul><li>La clase en pseudo-código es casi una entidad. Para que sea completamente una entidad es necesario asociarla con un EntityManager
  39. 39. EntityManager: se refiere a una API que ofrece los servicios requeridos para trabajar con una entidad
  40. 40. En J2SE se define un EntityManager de la siguiente manera (explícita): </li></ul>EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(“PersistentUnitName”); EntityManager eManager = entityManagerFactory.createEntityManager();
  41. 41. EntityManager <ul><li>En J2EE se emplea una anotación en la clase de la entidad que se desea manejar y el contenedor (Servidor de Aplicaciones) se encarga del resto: </li></ul>@Resource private EntityManager entityManager;
  42. 42. Persistence Context <ul><li>Un contexto de persistencia administra un conjunto de entidades que a su vez es manejado por un EntityManager. El contexto de persistencia lleva el registro del estado y/o los cambios que puedan ocurrirle a una entidad. El EntityManager por su parte hace uso de los servicios que provee el contexto de persistencia para enviar (commit) o deshacer estos cambios. Tan pronto como se crea un objeto EntityManager éste es asociado implícitamente con el contexto de persistencia correspondiente. </li></ul>
  43. 43. Entidades y Transacciones <ul><li>Todas las entidades cuentan con la propiedad de ser transaccionales. Todas sus operaciones CRUD se realizan en un contexto transaccional. Existen dos clases principales de transacciones: JTA y Resource-local
  44. 44. Con las transacciones JTA el programador no debe preocuparse por nada, pero en las transacciones tipo Resource-local las validaciones corren por su cuenta y basado en los resultados de las mismas debe determinar si envía una transacción (commit) o por el contrario la anula (roll-back) </li></ul>
  45. 45. Operaciones sobre Entidades <ul><li>Persistencia: </li></ul><ul><li>postEntity postObject = new postEntity();
  46. 46. postObject.set();//definir valores para el objeto
  47. 47. entityManager.persist(postObject); </li></ul>
  48. 48. Operaciones sobre Entidades II <ul><li>Consultas: el programador está en libertad de usar objetos EntityManager para consultas simples u objetos Query para consultas más complejas
  49. 49. find() es un método propio de la clase EntityManager y permite recuperar una instancia de una entidad empleando el nombre de la clase y la llave primaria: </li></ul>postEntity elPost = entityManager.find(postEntity.class, 1); If (elPost != null){ // post object puede o no ser null. // Procesar el objecto }
  50. 50. Operaciones sobre Entidades III <ul><li>delete() es el método de la clase EntityManager que permite eliminar una instancia de una entidad: </li></ul>postEntity elPost = entityManager.find(postEntity.class, 1); if (elPost != null){ // post object puede o no ser null. // eliminar el objecto EntityManager.remove(elPost); }
  51. 51. Operaciones sobre Entidades IV <ul><li>update() es el método de la clase EntityManager que permite actualizar una instancia de una entidad: </li></ul>postEntity elPost = entityManager.find(postEntity.class, 1); If (elPost != null){ // post object puede o no ser null. // modificar los atributos del objecto con los metodos set elPost.setTitle(&quot;Un nuevo titulo&quot;); EntityManager.merge(elPost); }
  52. 52. Operaciones sobre Entidades V <ul><li>flush() es el método que sincroniza los cambios realizados sobre una entidad con la base de datos: </li></ul>postEntity elPost = entityManager.find(postEntity.class, 1); If (elPost != null){ // post object puede o no ser null. // modificar los atributos del objecto con los metodos set elPost.setTitle(&quot;Un nuevo titulo&quot;); EntityManager.merge(elPost); EntityManager.flush(); }
  53. 53. Operaciones sobre Entidades VI <ul><li>refresh() es el método que devuelve los atributos de un objeto al último estado recuperado desde la base de datos: </li></ul>postEntity elPost = entityManager.find(postEntity.class, 1); If (elPost != null){ // post object puede o no ser null. // modificar los atributos del objecto con los metodos set elPost.setTitle(&quot;Un nuevo titulo&quot;); EntityManager.merge(elPost); EntityManager.refresh(); }
  54. 54. find() no es muy flexible <ul><li>Es claro que contar con la posibilidad de recuperar instancias de una entidad, exclusivamente utilizando su llave primaria, no es adecuado en prácticamente ningún ambiente. Para superar este obstáculo es necesario emplear JPQL, un lenguaje de consultados basado en SQL y orientado a objetos
  55. 55. Existen 2 tipos de consultas diferentes: estáticas y dinámicas </li></ul>
  56. 56. Static Query <ul><li>Una consulta estática se define empleando XML justo antes de la definición de la clase de la entidad. Este tipo de consultas llevan un nombre gracias al cual otros componentes de la misma unidad de persistencia pueden usarla: </li></ul>@NamedQuery(name = ” PostEntity.findAll” query = “SELECT M FROM POSTENTITY”) @Entity class PostEntity{ }
  57. 57. Static Query II <ul><li>Luego de definida, una consulta estática puede utilizarse de la siguiente manera: </li></ul>Query findAllQuery = entityManager. createNamedQuery(“PostEntity.findAll”) ;
  58. 58. Static Query III <ul><li>También es posible definir arreglos de consultas estáticas para usarlos luego: </li></ul>@NamedQueries( { @NamedQuery(name = “Post.selectAllQuery” query = “SELECT M FROM POSTENTITY”), @NamedQuery(name = “Post.deleteAllQuery” query = “DELETE M FROM POSTENTITY”) } )
  59. 59. Dynamic Query <ul><li>Una consulta dinámica se define dentro del código de la entidad, empleando código SQL corriente. Aunque a primera vista puede resultar más simple que definir consultas estáticas, su uso puede disminuir en gran medida el desempeño de la aplicación ya que todo el mapeo de objetos / base de datos ocurre en tiempo de ejecución: </li></ul>Query singleSelectQuery = entityManager.createQuery( “SELECT M FROM MOBILEENTITY WHERE M.IMEI = ‘ABC-123’”);
  60. 60. Trabajando con los resultados <ul><li>Una consulta puede traer un resultado, en cuyo caso se accede a el de la siguiente manera: </li></ul><ul><li>PostEntity postObj = singleSelectQuery. getSingleResult() ; </li></ul><ul><li>O puede traer múltiples resultados en cuyo caso es necesario convertir (cast) el resultado a un objeto tipo Lista: </li></ul><ul><li>List posts = (List)multipleSelect. getResultList() ; </li></ul>
  61. 61. Parámetros para las Consultas <ul><li>Tanto las consultas dinámicas como las consultas estáticas pueden emplear parámetros dinámicos, los cuales son enviados en tiempo de ejecución: </li></ul><ul><li>@NamedQuery(
  62. 62. name = “Post.findByTitle”
  63. 63. query = “SELECT P FROM POSTENTITY WHERE P.TITLE LIKE '% :keyword %'
  64. 64. ) </li></ul><ul><li>Y luego en el código podría llamarse pasando el parámetro deseado: </li></ul><ul><li>Query namedQuery = entityManager.createNamedQuery(“Post.findByTitle”);
  65. 65. namedQuery.setParameter(“keyword”, entradaUsuario); </li></ul>
  66. 66. Paginación de Resultados <ul><li>Si una consulta devuelve, por ejemplo, 1000 resultados. No es una buena idea devolver todo el conjunto de resultados al usuario de una sola vez, en lugar de esto deben dividirse los resultados en páginas de menor tamaño e ir retornando una página a la vez de acuerdo con las solicitudes del usuario </li></ul>
  67. 67. Paginación de Resultados int maxRecords = 10; int startPosition = 0; String queryString = “SELECT M FROM MOBILEENTITY”; while( true ){ Query selectQuery = entityManager.createQuery(queryString); selectQuery.setMaxResults(maxRecords); selectQuery.setFirstResult(startPosition); List mobiles = entityManager.getResultList(queryString); if (mobiles.isEmpty()){ break; } //Process the mobile entities. process(mobiles); entityManager.clear(); startPosition = startPosition + mobiles.size(); }
  68. 68. Unidades de Persistencia <ul><li>Unidad de Persistencia: una manera de categorizar un conjunto de entidades que trabajaran de forma conjunta y compartirán una misma configuración
  69. 69. Las unidades de persistencia se definen empleando archivos XML y deben asociarse a los objetos EntityManager: </li></ul><ul><li>@PersistentUnit(unitName = “MyPostPersistentUnit”)
  70. 70. private EntityManager entityManager; </li></ul>
  71. 71. Ejemplo: utilizando JPA para Blog <ul><li>Paso 1: crear una unidad de persistencia: </li><ul><li>Proveedor EclipseLink
  72. 72. DataSource: conexión con la base de datos del blog (si no existe crear) </li></ul><li>Paso 2: crear una clase para la entidad de la tabla (posts)
  73. 73. Paso 3: crear el Servlet para que el usuario pueda buscar
  74. 74. Paso 4: asociar el EntityManager al Servlet
  75. 75. Paso 5: definir el método de búsqueda y la interfaz </li></ul>
  76. 76. Creación Unidad Persistencia
  77. 77. Creación Unidad Persistencia
  78. 78. Creación Entidad
  79. 79. Creación Entidad
  80. 80. Creación Entidad
  81. 81. Creación Servlet
  82. 82. Creación Servlet
  83. 83. Creación Servlet
  84. 84. Asociando el EntityManager
  85. 85. Método de búsqueda para el Servlet <ul><li>public Posts findPostById(Integer auxPostId) {
  86. 86. Posts auxPost = null;
  87. 87. try {
  88. 88. Context ctx = (Context) new InitialContext().lookup(&quot;java:comp/env&quot;);
  89. 89. utx.begin();
  90. 90. EntityManager em = (EntityManager) ctx.lookup(&quot;persistence/LogicalName&quot;);
  91. 91. //em.persist(object);
  92. 92. auxPost = em.find(Posts.class, auxPostId);
  93. 93. utx.commit();
  94. 94. } catch (Exception e) {
  95. 95. Logger.getLogger(getClass().getName()).log(Level.SEVERE, &quot;exception caught&quot;, e);
  96. 96. throw new RuntimeException(e);
  97. 97. }
  98. 98. return auxPost;
  99. 99. } </li></ul>
  100. 100. Interfaz de búsqueda Servlet <ul><li>try {
  101. 101. // TODO output your page here
  102. 102.
  103. 103. out.println(&quot;<h1>Motor de Busqueda - Blog</h1>&quot;);
  104. 104. String uiAuxId = request.getParameter(&quot;post_id&quot;);
  105. 105. if (uiAuxId != null && !uiAuxId.isEmpty()) {
  106. 106. //resultados de la busqueda
  107. 107. Posts resultadoBusqueda = this.findPostById(Integer.parseInt(uiAuxId));
  108. 108. if (resultadoBusqueda != null) {
  109. 109. out.println(&quot;<table>&quot;);
  110. 110. out.println(&quot;<tr>&quot;);
  111. 111. out.println(&quot;<td>Resultado de su b&uacute;squeda:</td>&quot;);
  112. 112. out.println(&quot;<td>&quot; + resultadoBusqueda.getPostTitle() + &quot;</td>&quot;);
  113. 113. out.println(&quot;</tr>&quot;);
  114. 114. out.println(&quot;</table>&quot;); </li></ul>
  115. 115. Interfaz de búsqueda Servlet <ul><li>} else {
  116. 116. out.println(&quot;<table>&quot;);
  117. 117. out.println(&quot;<tr>&quot;);
  118. 118. out.println(&quot;<td>Su b&uacute;squeda no arrojo resultados</td>&quot;);
  119. 119. out.println(&quot;</tr>&quot;);
  120. 120. out.println(&quot;</table>&quot;);
  121. 121. }
  122. 122. } else {
  123. 123. //formulario de busqueda
  124. 124. out.println(&quot;<form method='POST' action='./SearchPost'>&quot;);
  125. 125. out.println(&quot;<table>&quot;);
  126. 126. out.println(&quot;<tr>&quot;);
  127. 127. out.println(&quot;<td>Codigo del Post:</td>&quot;);
  128. 128. out.println(&quot;<td><input type='text' name='post_id'></td>&quot;);
  129. 129. out.println(&quot;</tr>&quot;);
  130. 130. out.println(&quot;<tr>&quot;);
  131. 131. out.println(&quot;<td colspan='2'><input type='submit' name='sendBtn' label='Search'></td>&quot;);
  132. 132. out.println(&quot;</tr>&quot;);
  133. 133. out.println(&quot;</table>&quot;);
  134. 134. out.println(&quot;</form>&quot;);
  135. 135. } </li></ul>
  136. 136. Y si quisiéramos añadir un post? <ul><li>Paso 1: añadir un nuevo Servlet
  137. 137. Paso 2: definir la unidad de persistencia
  138. 138. Paso 3: implementar en él un método que permita recuperar el último id empleado
  139. 139. Paso 4: implementar la interfaz gráfica </li></ul>
  140. 140. Método para recuperar el último id <ul><li>protected Integer getLastId(){
  141. 141. Posts postAux = null;
  142. 142. try {
  143. 143. Context ctx = (Context) new InitialContext().lookup(&quot;java:comp/env&quot;);
  144. 144. utx.begin();
  145. 145. EntityManager em = (EntityManager) ctx.lookup(&quot;persistence/LogicalName&quot;);
  146. 146. //em.persist(object);
  147. 147. Query findAllQuery = em.createNamedQuery(&quot;Posts.findAll&quot;);
  148. 148. List posts = findAllQuery.getResultList(); </li></ul>
  149. 149. Método para recuperar el último id <ul><li>//para recorrer una lista se requiere un iterador
  150. 150. Iterator auxiliar = posts.iterator();
  151. 151. while(auxiliar.hasNext()){
  152. 152. postAux = (Posts)auxiliar.next();//cast
  153. 153. }
  154. 154. utx.commit();
  155. 155. } catch (Exception e) {
  156. 156. Logger.getLogger(getClass().getName()).log(Level.SEVERE, &quot;exception caught&quot;, e);
  157. 157. throw new RuntimeException(e);
  158. 158. }
  159. 159. return postAux.getPostId();
  160. 160. } </li></ul>
  161. 161. Interfaz Servlet (antes de submit) <ul><li>} else {
  162. 162. //formulario para la creacion de un nuevo post
  163. 163. out.println(&quot;<form method='POST' action='./ NewPost '>&quot;);
  164. 164. out.println(&quot;<table>&quot;);
  165. 165. out.println(&quot;<tr>&quot;);
  166. 166. ...
  167. 167. out.println(&quot;<tr>&quot;);
  168. 168. out.println(&quot;<td colspan='2'><input type='submit' name='btnSubmit' value='savePost' label='Save'></td>&quot;);
  169. 169. out.println(&quot;</tr>&quot;);
  170. 170. out.println(&quot;</table>&quot;);
  171. 171. out.println(&quot;</form>&quot;);
  172. 172. }
  173. 173. out.println(&quot;</body>&quot;);
  174. 174. out.println(&quot;</html>&quot;); </li></ul>
  175. 175. Interfaz Servlet (después de submit) <ul><li>if (request.getParameter(&quot;btnSubmit&quot;) != null && request.getParameter(&quot;post_title&quot;) != null &&
  176. 176. request.getParameter(&quot;post_date&quot;) != null && request.getParameter(&quot;post_body&quot;) != null) {
  177. 177. Posts nuevoPost = new Posts();
  178. 178. … //manipulacion de la fecha
  179. 179. nuevoPost.setPostDate(fechaSql);
  180. 180. nuevoPost.setPostTitle(request.getParameter(&quot;post_title&quot;));
  181. 181. nuevoPost.setPostBody(request.getParameter(&quot;post_body&quot;));
  182. 182. nuevoPost.setPostId(this.getLastId()+1);
  183. 183. this.persist(nuevoPost);
  184. 184. response.sendRedirect(&quot;./SearchPost&quot;); </li></ul>

×