martes, 14 de julio de 2020

La API de JPA 2.1 (VI) Persistence.xml, definiendo la conexión a algunas BDs. Maven multimódulo

Veamos como solucionar algunos casos que me han pasado y que me han requerido bastante tiempo para solucionarlos o al menos para medianamente entenderlos. Recordar que en "maven", le persistence.xml es conveniete colocarlos en "src/main/resources

Caso 1º. Acceso a H2 (en linux). Ruta absoluta


En este caso , nuestra base de datos está situado en el directorio DB del directorio del usuario (/home/usuario) y se llama "myh2", en el persistence.xml se tenía:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<persistence-unit name="myh2" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
     
  <properties>
    <!-- (FUNCIONA EN MODO LOCAL) property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/DBs/myh2" /> -->
    <!-- (FUNCIONA EN MODO LOCAL) property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://192.168.100.100/~/DBs/myh2" /> -->
    <!-- OJO una ruta absoluta necessita // despres del server !!! -->
    <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://192.168.100.100//home/eduard/DBs/myh2" />
    <property name="javax.persistence.jdbc.user" value="myuser"/>
    <property name="javax.persistence.jdbc.password" value="mypassword"/>
    <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
    <!-- <property name="hibernate.hbm2ddl.auto" value="update" /> -->
    <property name="javax.persistence.schema-generation.database.action" value="none"/>
  
    <!-- Provider specific properties -->
    <property name="hibernate.show_sql" value="true" />
    <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
            
			        
  </properties>
      
 </persistence-unit>


Se pueden ver como en las líneas  5 y 6 se puede acceder de forma local y usando el mismo usuario (pues se está usando el símbolo "~" que indica que es el directorio del usuario que se ha conectado. Si nos conectamos como otro usuario, la conexión falla.

Para evitarnos sustos debemos indicar la ruta absoluta como se indica en la línea 8, donde despues de la dirección del server (o del puerto del server si se ha indicado), hay que dar doble barra "//

Caso 2º. Acceso a una BD Postgres por JNDI

JNDI permite asociar nombres a objectos. Estos objetos pueden ser contenedores de datos. En este caso particular, le decimos a nuestro Tomcat que sea él el encargado de gestionar la connexión a la base de datos. Veamos el "persistence.xml".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<persistence-unit name="jndi_postgres" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
  <!-- BEGIN: FOR Data Source in Tomcat -->
  <jta-data-source>java:comp/env/mypostgres</jta-data-source>
      
  <!--????? OJO: Revisar el context.xml de webapp/META-INF que apunta al servidor 192.168.100.101 -->
        
  <!-- END:   FOR Data Source in Tomcat-->
  <properties>
    <property name="hibernate.dialect"	value="org.hibernate.dialect.PostgreSQLDialect" />
    <property name="hibernate.hbm2ddl.auto" value="update" />
    <property name="hibernate.show_sql" value="true" />				  
  </properties>
    
</persistence-unit>

Observar la línea 4 que tiene la etioqueta "<jta-data-source> le descarga la responsabilidad al JDNI. La nomenclatura empleada es "java:comp/env/nombre_recurso"

Ahora muchas propiedades han desaparecido, ya que se supone que se encarga el JNDI de apañárselas.

Para definir el JNDI, en Deployed Resources - webapp - META_INF tenemos que crear el fichero "context.xml" 



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/mypath" docBase="mypath" debug="5" reloadable="true" crossContext="true">
        
   
    <!-- PRIMER RECURSO (el que hace referencia en persistence.xml-->
    <Resource 
      name="mypostgres"
      auth="Container"
      type="javax.sql.DataSource"
      username="mysuser"
      password="mypassword"
      maxTotal="50"
      maxIdle="20"
      maxWait="10000"
      timeBetweenEvictionRunsMillis="180000"
      removeAbandonedOnMaintenance="true"
      removeAbandonedOnBorrow="true"
      driverClassName="org.postgresql.Driver"
      url="jdbc:postgresql://192.168.100.101:5432/mypostgresdb" 
    />

    <!-- SEGUNDO RECURSO -->
    <Resource 
      name="mypostgres2"
      auth="Container"
      type="javax.sql.DataSource"
      username="mysuser2"
      password="mypassword2"
      maxTotal="50"
      maxIdle="20"
      maxWait="10000"
      timeBetweenEvictionRunsMillis="180000"
      removeAbandonedOnMaintenance="true"
      removeAbandonedOnBorrow="true"
      driverClassName="org.postgresql.Driver"
      url="jdbc:postgresql://192.168.100.102:5432/mypostgres2db" 
    />
      
    
</Context>


Como se puede ver, se pueden definir múltiples recursos, en este caso el primero es el que hace referencia el "persistence.xml". Se observa que se ha delegado la URL de acceso a la BD al "context.xml".

Caso 3º. Maven multimódulo, no puede mapear las clases!

El proceso de mapeado (reconocimiento) de las clases que entran en juego en la persistencia, es un poco complejo. En principio no hay ningun problema cuanto tenemos un olo módulo maven y una sola "persistence unit".

Cuando complicamos un poco la cosa y le metemos una segunda "persistence unit" en el "persistence.xml", a la hora de crear las clases automáticamente, se lia la cosa y crea las clases en las 2 persistence units a la vez. Para solucionar esto, se puede hacer:
  1. Trabajar con esquemas, onde le decimos cada clase a que esquema pertenece.
  2. Definir con la etiqueta <class> cada clase que interviene en cada persistence unit.
Si ademas tenemos bastantes módulos y las clases de cada persistence unit las tenemos separadas en módulos... entonces únicamente he podido conseguir que mapaeara las clasess creando una etiqueta <class> con cada una de las clases a mapear en el persistence unit. Si alguien encuentra una solución mejor que me lo diga. También se podria utilizar la etiqueta <jar-file> si somos capaces de crear un jar de cada módulo.