JPA használata Java SE alkalmazásban (CDI-vel)

Posted by | · · · · | Egy csésze kávé · Szoftverfejlesztés | Nincs hozzászólás a(z) JPA használata Java SE alkalmazásban (CDI-vel) bejegyzéshez

A CDI használata Java SE alkalmazásban bejegyzésben bemutattam hogyan készíthetünk CDI-t használó Java SE alkalmazást. Ebben és a következő néhány bejegyzésben pedig meg szeretném mutatni, hogyan hozhatunk létre olyan JPA-t használó Java SE alkalmazást, amelyben felhasználjuk a CDI nyújtotta lehetőségeket.

 

A Java Persistence API (JPA) specifikációja lehetőséget szolgáltat relációs adatok kezelésére java alkalmazásokban. A JPA része az EJB 3.0 specifikációnak, de nincs korlátozva csak arra, így felhasználható a Java EE környezeten kívül is, például Java SE alkalmazásokban is.

 

A JPA-nak több implementációja is rendelkezésünkre áll (Hibernate, EclipseLink, stb.). Ezek közül az EclipseLink-et választottam. Adatbázisnak pedig a H2-őt. A H2-re azért esett a választásom, mert van embedded módja.

Projekt konfigurálása

A következő két függőséget adjuk hozzá maven projektünkhöz:

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.6.0</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.190</version>
    <scope>compile</scope>
</dependency>

A következő lépés, hogy létrehozzuk a persistence.xml fájlt. Ennek helye src/main/resources/META-INF/ könyvtár. A persistence.xml fájl a JPA úgynevezett deployment descriptor fájlja. Itt adhatóak meg a persistence unit-ok és deklarálhatóak a kezelt persistence osztályok, továbbá itt adhatók meg az adatbázis kapcsolat adatai.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.ddl-generation" value="create-tables"/>
            <property name="eclipselink.logging.level.sql" value="FINEST"/>
            <property name="eclipselink.logging.parameters" value="true"/>
            
            <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.H2Platform"/>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:./data/sample"/>
            <property name="javax.persistence.jdbc.password" value="admin" />
            <property name="javax.persistence.jdbc.user" value="admin" />
        </properties>
    </persistence-unit>
</persistence>

A fenti persistence.xml fájlból a következők olvashatóak ki:

  • Definiálunk egy default névvel ellátott persistence unit-ot. A persistance unit egy logikai csoportosítása a persistence osztályoknak (entity class-ok, embeddable class-ok és mapped superclass-ok). Ezen persistence unit-nak a transaction-type-ját RESOURCE_LOCAL-nak állítjuk be. A JPA két módszert szolgáltat a tranzakció kezelésre: a JTA-t és a RESOURCE_LOCAL-t. A JTA (Java Transaction API) Java EE alkalmazásokban használhatjuk managed módban (EJB). Nem managed módra szolgál a RESOURCE_LOCAL. Így aztán Java SE alkalmazásban ezt használhatjuk. A nem managed mód azt jelenti, hogy magunknak kell kezelnünk a tranzakciókat, míg managed módban az EJB container végzi ezt. További információkért ajánlom a következő linket: Java Persistence/Transactions
  • A provider attribútum határozza meg a JPA EntityManager implementációját. Az EntityManager java doc-ja:

    public interface EntityManager
    Interface used to interact with the persistence context.

     

    An EntityManager instance is associated with a persistence context. A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed. The EntityManager API is used to create and remove persistent entity instances, to find entities by their primary key, and to query over entities.

     

    The set of entities that can be managed by a given EntityManager instance is defined by a persistence unit. A persistence unit defines the set of all classes that are related or grouped by the application, and which must be colocated in their mapping to a single database

  • A persistence osztályok meghatározása. Van lehetőségünk explicite megadni a persistence osztályokat, amelyeket a persistence unit-ban kezelni szeretnénk. Erre a <class> tag használható. Amennyiben nem szeretnénk válogatni, hanem az összes persistence osztályunkat az alkalmazásunkban egy persistence unit-ban szeretnék használni, akkor használhatjuk a következőt: <exclude-unlisted-classes>false</exclude-unlisted-classes> ezzel megadva, hogy nem kívánjuk kizárni a nem felsorolt persisctence osztályokat.
  • Az eclipselink.ddl-generation property-nek a create-tables értéket adtam meg, amely azt jelenti, hogy alkalmazás induláskor az eclipselink létrehozza a szükséges adatbázis táblákat. További lehetőségeket megtekintheted itt.
  • Adatbázis kapcsolat adatainak megadása a javax.persistence.jdbc.* property-kkel lehetséges.

Összefoglalva a fenti persistence.xml-ben egy default nevű, nem managed (RESOURCE_LOCAL) tranzakció kezelésű persistence unit-ot definiáltunk, mely egy H2 adatbázishoz csatlakozik, amely egy data nevű könyvtáron belül, sample névvel fog létrejönni az alkalmazás első indulásakor. Az adatbázis táblákat pedig az eclipselink hozza létre.

EntityManager létrehozása

A RESOURCE_LOCAL transaction-type esetén mi vagyunk felelősek az EntityManager létrehozásáért és kezeléséért.

  • Az EntityManagerFactory-t kell használnunk, hogy egy EntityManager példányhoz jussunk
  • Az EntityTransaction API-t kell használnunk a tranzakció kezeléshez, minden EntityManager metódus hívás egy tranzakció indítás és lezárás közt kell szerepeljen.
  • Az entityManagerFactory.createEntityManager() kétszeri hívása két külön EntityManager példányt fog eredményezni.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("default");
EntityManager entityManager = emf.createEntityManager();

A fenti kódrészlet megmutatja, hogyan tudunk létrehozni egy EntityManagerFactory-t a default nevű persistance unit-unkhoz, majd hogyan használhatjuk fel, hogy létrehozzunk egy EntityManager példányt.

 

Mivel CDI-s alkalmazásban szeretnénk használni a JPA-t, ezért igen praktikus volna, ha az EntityManager-t is tudnánk injektálni. Azonban mivel egy EntityManager létrehozásához kell egy EntityManagerFactory is, így injektálni nem tudjuk olyan egyszerűen.

 

A CDI a producer metódusok segítségével lehetőséget ad nekünk arra, hogy megadhassuk a container-nek miként példányosítson egy objektumot, s így injektálhatóvá tehetjük számunkra az EntityManager-t.

import java.util.logging.Logger;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.jboss.weld.environment.se.events.ContainerInitialized;

@ApplicationScoped
public class EntityManagerProducer {

    private EntityManagerFactory emf;

    public void init(@Observes ContainerInitialized containerInitialized) {
        emf = Persistence.createEntityManagerFactory("default");
    }

    @Produces
    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void closeEntityManager(@Disposes EntityManager entityManager) {
        entityManager.close();
    }
}

Az EntityManagerProducer osztályt ApplicationScoped-ossá tettem, hogy egy és csak egy példány létezzen belőle. Felhasználtam a ContainerInitialized event-et annak érdekében, hogy elkérjem a default nevű persistence unit-hoz az EntityManagerFactory-t. A @Produces annotációval ellátott metódus felelős az EntityManager létrehozásáért. A container ezt a metódust használja fel, hogy EntityManager-t injektálhasson.

@Inject
private EntityManager em;

Fontos észrevennünk, hogy ezen implementáció azt eredményezi, hogy minden egyes injectionpont-hoz egy új EntityManager fog létrejönni. Ez majd a későbbiekben fontos lesz.

Összegzés

A jelenlegi bejegyzésben eljutottunk odáig, hogy tudunk EntityManager-t injektálni CDI-t használó Java SE alkalmazásban. A következő lépés a tranzakció kezelés lesz, melyet a következő bejegyzésben fogok tárgyalni.


No Comments

Leave a comment