Advanced Java Services | Entity Beans 3.0 |
Einführung
Eine Entity Bean ist mit der Version 3.0 nicht nur ein POJO (plein old java object) geworden sondern kann
auch völlig unabhängig von einem BeanContainer (Glassfish, JBoss etc.) agieren. Deshalb spricht man nun auch
manchmal nur von Entities statt von Entity Beans. Geblieben ist, daß ein Objekt einer Entityklasse einer Zeile einer
Zeile einer Tabelle einer relationalen Datenbank entspricht. Zwei wichtige Hilfsklassen bzw. Interfaces
und eine xml-Datei regeln den Zugriff auf die gewählte Datenbank. Dies entspricht der früheren CMP
(container managed persistence). Eine BMP (bean maanged persistence) exisiert in diesem Sinne nicht mehr.
Der Verbindungsaufbau und die gesamte Datenmanipulation (Persistenz) werden von einer Hilfsklasse erledigt
die das Interface javax.persistence.EntityManager implementiert hat. Ein Objekt vom Typ EntityManager
erhält man über eine EntityManagerFactory. Eine Implementierung des Interfaces javax.persistence.EntityManagerFactory
muß u.a. die Methode createEntityManager() bereitstellen, die das vollbringt was ihr Name erwarten läßt.
Die Factory selbst wiederum erhält man über eine weitere Hilfsklasse, die Klasse javax.persistence.Persistence
Diese Klasse stellt u.a. die statische Methode createEntityManagerFactory(java.lang.String persistenceUnitName)
bereit, mit der man eine Factory erzeugen kann.
Wo findet man die Interfaces und die Implementierungen
Die Interfaces javax.persistence.EntityManager und javax.persistence.EntityManagerFactory sowie
die Klasse javax.persistence.Persistence liegen im Archiv javaee.jar, das nach der Installation
von Glassfish im Installationsverzeichnis zu finden ist. Die Implementierungen der Interfaces heißen
oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl und
oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerImpl und befinden sich im Archiv
toplink-essentials.jar. Auch dieses Archiv findet man im Glassfishverzeichnis. Dieses Archiv wird dort ergänzt
durch toplink-essentials-agent.jar in dem sich weitere notwendige Hilfsklassen befinden.
Links zu den Archiven
Das Archiv javaee.jar gibt es auch hier.
Die toplink-essentials.jar gibt es auch hier.
Die Beispiele
Es folgen vier Beispiele, die das Grundsätzliche abdecken sollen. Mit dieser Grundlage können dann auch kompexere
Beispiele realisiert werden.
Wir werden alle Beispiele ohne Netbeans und ohne Eclipse entwickeln. Stattdessen arbeiten wir mit einem einfachen
Editor, etwa mit Textpad. So wird das Zusammenspiel der einzelnen Komponenten am deutlichsten. Der Übergang zu
Eclipse sollte dann kein Problem darstellen. Des weiteren verzichten wir der Einfachheit halber darauf die
Javaklassen bzw. Interfaces in Packages zu legen. Als Übung können Sie das Beispiel so abändern, daß Sie Packages
einsetzen. In der Praxis werden die Klassen immer in Packages gelegt.
1) Entity wird auf lokale Datenbanktabelle abgebildet (MySQL)
Unser erstes Beispiel besteht im wesentlichen aus vier Dateien, einer Entityklasse (Movie), einem EntityHandler
(MovieHandler), der Hauptklasse ConnectToMovieDB, die in main() den EntityManager bereitstellt und einer (notwendigen) xml-Datei
mit dem Namen persistence.xml, in der der Datenbankzugriff konfiguriert wird. Diese Datei muß in einem eigenen Verzeichnis
mit dem Namen META-INF untergebracht sein. Dieses Verzeichnis enthält noch die immer notwendige aber simple Datei
MANIFEST.MF. Damit ergibt sich die folgende Struktur
beispiel-1 <dir> | --- Movie.class <file> --- MovieHandler.class <file> --- ConnectToMovieDB.class <file> --- META-INF <dir> | --- MANIFEST.MF <file> --- persistence.xml <file>
Die Entity Movie
/* entity class @Entity (necessary) declares the class as an entity bean (i.e. a persistent POJO class), this class needs to be mapped to a relational database table. @Id (necessary) declares the identifier property of this entity bean. @GeneratedValue indicates that the server automatically generates the primary key value. @Table (optional) defines the table name. Each instance of the entity bean represents a row of data in the table. is set at the class level; it allows you to define the table, catalog, and schema names for your entity bean mapping. If no @Table is defined the default values are used, that is the unqualified class name of the entity. @SequenceGenerator(name = "movie-sequence", sequenceName = "movie-id") (optional) The @SequenceGenerator defines a sequence generator. A sequence is a database feature. It returns the next Integer or Long value each time it is called. */ import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Entity; //import javax.persistence.Column; import javax.persistence.GeneratedValue; @Entity @Table(name="moviedatabase") public class Movie { @Id @GeneratedValue private int id; private String director; private String title; private int year; public Movie() { id = year = 0; director = title = ""; } public Movie(String director, String title, int year) { this.director = director; this.title = title; this.year = year; } public int getId() { return id; } //@Column(name="director") public String getDirector() { return director; } public void setDirector(String director) { this.director = director; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } }
Der EntityManager erstellt aus dieser Klasse eine Tabelle mit dem Namen "moviedatabase" mit den Spalten
ID (INTEGER), DIRECTOR (VARCHAR), TITLE (VARCHAR), YEAR (INTEGER). Man kann aber die Spaltentitel
mit der Annotation @Column auch selbst bestimmen.
Der MovieHandler
Diese Klasse stellt die notwendigen Methoden bereit um die Tabelle zu bearbeiten.
/* ermöglicht aufnehmen, löschen und ausgeben in die tabelle, die zur entity Movie gehört */ import java.util.List; import javax.persistence.Query; import javax.persistence.EntityManager; public class MovieHandler { private EntityManager em; public MovieHandler(EntityManager entityManager) throws IllegalArgumentException { if (entityManager == null) throw new IllegalArgumentException("entityManager cannot be null"); em = entityManager; } public void addMovie(Movie movie) { em.getTransaction().begin(); em.persist(movie); em.getTransaction().commit(); } public boolean deleteMovie(Object primaryKey) { Movie movie = em.find(Movie.class,primaryKey) ; if (movie!=null) { em.remove(movie); return true; } return false; } public List<Movie> listMovies() { Query query = em.createQuery("SELECT m from Movie as m"); return query.getResultList(); } } // end MovieHandler
Die Klasse arbeitet mit dem EntityManager zusammen. Dieser stellt die notwendigen Methoden bereit um auf die
datenbank zuzugreifen, nachdem die Tabelle érstellt worden ist. Für Datenbankabfragen gibt es eine eigne
Abfragesprache, Java Persistence Query Language, siehe hierzu den
Wikipediaeintrag.
Die Mainklasse ConnectToMovieDB
/* Main class arbeitet zusammen mit Movie, MovieHandler, persistence.xml um die anwendung laufen zu lassen braucht man javaee.jar toplink-essentials.jar toplink-essentials-agent.jar mysql-connector-java-5.1.12-bin.jar szenario 1 ----------------- startet man über textpad, so müssen die dateien um ext-verzeichnis des jdk liegen startet man über die konsole oder eclipse, so müssen die dateien im ext-verzeichnis der jre liegen szenario 2 ----------------- man erstellt ein startbares jar-file. aufruf mit java -jar <myJarName>.jar beim aufruf erzeugt der manager die beiden hilfsdateien createDDL.jdbc dropDDL.jdbc sie enthalten die SQL-statements zum anlegen und ändern der tabellen */ import java.util.List; import java.util.Iterator; import javax.persistence.Query; import javax.persistence.Persistence; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; public class ConnectToMovieDB { private static String PERSISTENCE_UNIT_NAME = "movies"; private static EntityManagerFactory emf; private static EntityManager em; public static void main(String[] args) { em = createEntityManager(); System.out.println("EntityManager = " + em.getClass().getName()); MovieHandler mh = new MovieHandler(em); List<Movie< list = mh.listMovies(); printMovies(list); Movie movie = new Movie("fritz lang","metropolis", 1927); mh.addMovie(movie); list = mh.listMovies(); printMovies(list); close(); } private static EntityManager createEntityManager() { String PERSISTENCE_UNIT_NAME = "movies"; System.out.println("---- about to create EntityManagerFactory ----"); emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); System.out.println("EntityManagerFactory = " + emf.getClass().getName()); System.out.println("------- about to create EntityManager --------"); return emf.createEntityManager(); // ergibt ein warning } private static void close() { System.out.println("------------ close EntityManager -------------"); em.close(); System.out.println("--------- close EntityManagerFactory ---------"); emf.close(); } public static void printMovies(Listlist) { if( list.size() == 0) { System.out.println("--------- no movies in the database ----------"); return; } Iterator iter = list.iterator(); while(iter.hasNext()) { Movie movie = (Movie)iter.next(); System.out.println(movie.getId() ); System.out.println(movie.getDirector() ); System.out.println(movie.getTitle() ); System.out.println(movie.getYear() ); } } } // end ConnectToMovieDB
Die Datei persistence.xml
In dieser Datei wird der Zugriff auf die datenbank konfiguriert.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="movies" transaction-type="RESOURCE_LOCAL"> <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider> <class>Movie</class> <properties> <property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/test"/> <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="toplink.jdbc.user" value="myPW"/> <property name="toplink.jdbc.password" value="myPW"/> <property name="toplink.ddl-generation" value="drop-and-create-tables"/> </properties> </persistence-unit> </persistence>
Damit haben wir alle Bausteine erstellt. Der Datenbanktreiber muß genauso wie die anderen erwähnten Archive
im passenden ext-Verzeichnis (jre und/oder jdk) liegen oder über einen CLASSPATH bekanntgemacht werden.
Screenshot des Ablaufs
2) Entity wird auf remote Datenbanktabelle abgebildet (MySQL)
Für unser zweites Beispiel können wir alle Javaklassen des vorigen Beispiels übernehmen. Lediglich die Datei
persistence.xml muß angepaßt werden. Hier die veränderte Datei.
Die Datei persistence.xml
Wir müssen hier nur die neue IP-Adresse eintragen, alles andere bleibt wie vorher.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="movies" transaction-type="RESOURCE_LOCAL"> <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider> <class>Movie</class> <properties> <property name="toplink.jdbc.url" value="jdbc:mysql://<my-server-ip>:3306/test"/> <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="toplink.jdbc.user" value="myPW"/> <property name="toplink.jdbc.password" value="myPW"/> <property name="toplink.ddl-generation" value="drop-and-create-tables"/> </properties> </persistence-unit> </persistence>
Man beachte, daß der Datenbanktreiber beim Client liegt.
Remote-Zugriff erlauben
Auf dem Server muß MySQL so konfiguriert sein, daß auch nichtlokale Zugriffe erlaubt sind. Wir starten daher die Konfigurierung erneut und verändern die Einstellung wie folgt:
Screenshot des Ablaufs
Der Screenshot unterscheidet sich nicht vom vorigen Beispiel.