Java Persistence API w samodzielnej aplikacji
Z Jacek Laskowski - Wiki Projektanta Java EE
Po poprzednich pozytywnych wynikach pracy z NB (NetBeans IDE 5.5), GF (Glassfish V2 B19), JSF (JavaServer Faces 1.2) i EJB (Enterprise JavaBeans 3.0, a właściwie JPA - Java Persistence API) postanowiłem spróbować uruchomić kolejną aplikację, która nie korzystałaby z usług serwera aplikacyjnego, a nadal korzystała z JPA.
Spis treści |
Wprowadzenie do Java Persistence API (JPA)
Java Persistence API (JPA) jest częścią specyfikacji Enterprise JavaBeans 3.0, która odpowiada za udostępnienie usług związanych z trwałym zapisem modelu aplikacji. JPA jest wynikiem pracy grup związanych z produktami (np. Hibernate, Oracle TopLink) oraz specyfikacjami (np. EJB 2.1, Java Data Object (JDO)), których celem było uproszczenie zapisu danych obiektowych w relacyjnych bazach danych. Przewrotna natura człowieka ma swoje odzwierciedlenie w tworzonych rozwiązaniach, gdzie zazwyczaj tworzymy aplikację obiektowo (w języu Java) podczas, gdy przechowujemy dane w sposób relacyjny. Próbą załagodzenia tego problemu była w architekturze Java EE 1.4 specyfikacja EJB 2.1 z częścią związaną z komponentami encyjnymi (ang. entity beans). Jednakże skomplikowane EJB 2.1 było nie do zaakceptowania, szczególnie w świetle innych alternatywnych rozwiązań. Powstał Hibernate później Spring Framework (a może powstały równocześnie, nie ma to większego znaczenia) i tak twórcy aplikacji Java EE powoli przenosili się do architektur nie-Java EE. Tworzenie aplikacji w Java EE 1.4 nie należało do najprostszych, a kombinacja Spring Framework + Hibernate była niezwykle łatwa i pomocna. Dni serwerów aplikacyjnych wydawały się policzone.
Kiedy to wydawało się, że część serwera aplikacyjnego wokół zapisu trwałego jest bezużyteczna i nikt, kto nie musiał, nie korzystał z komponentów encyjnych EJB, na scenie pojawiły się uproszczenia Java SE, które znacząco uprościły Java EE. Odrestaurowana specyfikacja Java EE 5 oparta o doświadczenia Spring Framework, Hibernate, JDO, kontenerów IoC (z reinkarnacją specyfikacji JavaBeans w postaci POJO) i nowymi dodatkami Java SE 5 (głównie Java Annotations) ponownie zaczęła zwraca na siebie uwagę. Możliwości Java EE 5 i łatwość tworzenia aplikacji prowokuje do zadania pytania, dlaczego nie można było stworzyć tego wcześniej, ale próbę odpowiedzi na to pytanie pozostawimy innym podczas, gdy my zajmiemy się aspektami praktycznymi (przy okazji, interesująco czytałoby się taki artykuł, czy nawet jakąś wiekszą rozprawę, a może nawet pracę magisterską na ten temat, ale ja nie zamierzam tego robić - na pewno nie teraz).
Po przydługim wstępie zaprezentujmy coś bardziej praktycznego, co pozwala przedstawić zalety jakie płyną z zastosowania ustandaryzowanych rozwiązań do realizacji naszych projektów. Poza tym, materiał zgromadzony tutaj, będzie punktem startowym do zaprezentowania Spring Framework i Hibernate w całkiem nowym świetle (dla przypomnienia, jestem zwolennikiem twierdzenia, że tworzenie aplikacji w środowisku Spring Framework + Hibernate nie różni się wcale od tworzenia aplikacji z Java EE 5, a ma wiele niedogodności w stylu braku ustandaryzowanych rozwiązań). Mimo zalet płynących ze stosowania serwera aplikacyjnego Java EE, tym razem wykorzystamy jedynie JPA, które ma możliwość pracy poza środowiskiem Java EE (podobnie jak np. Hibernate). I JPA, i Hibernate, pozwalają na pracę z relacyjnymi danymi w sposób obiektowy, jednakże tylko JPA udostępnia możliwość zanurzenia różnych implementacji mechanizmu trwałego zapisu, w tym i Hibernate. Innymi słowy Hibernate stał się jednym z wielu rozwiązań implementujących JPA i podobnie jak w przypadku JDBC, gdzie nie ma znaczenia z jaką bazą rozmawiamy, dzięki JPA nie ma znaczenia, kto konstruuje nam model na podstawie danych relacyjnych (korzystając wewnętrznie z JDBC). Ot, kolejna abstrakcja w dostępie do danych. Wcześniej mieliśmy JDBC - abstrakcję w dostępie do danych, na podstawie, których konstruowano model mapując kolumny do pól programistycznie, później nadeszła era rozwiązań ORM (Object-Relational Mapping), gdzie mapowania odbywały się deklaratywnie, które zaowocowały specyfikacją Java Persistence API (JPA) z możliwością włączania różnych ORMów (m.in. Hibernate).
Aplikacja JPA krok po kroku
Koniec teorii o JPA. Czas na naszą aplikację, która zobrazuje zastosowanie JPA w samodzielnej (ang. standalone) aplikacji. Przypomnę, że pracujemy w środowisku NetBeans IDE 5.5 (NB) z bibliotekami Glassfish (GF), które realizują JPA za pomocą Oracle TopLink (oczekuj opisu moich doświadczeń z JPA i Hibernate niedługo). Ważnym elementem aplikacji będzie zastosowanie JPA do zapisu trwałego bez konieczności uruchamiania serwera aplikacyjnego Java EE. JPA będąca częścią specyfikacji Java EE mogłaby sugerować, że jej jedyna możliwość zastosowania jest wyłącznie w ramach serwera aplikacyjnego, co zaraz zobaczysz jest nieprawdą.
Tworzenie projektu NB
Rozpoczynamy od stworzenia projektu w NB (File->New Project->General->Java Application).
Nasz projekt będzie nazywał się JpaStandalone, gdzie główna klasa należy (przypadkowo) do pakietu pl.jaceklaskowski.
i wciskamy przycisk Finish.
Tworzenie modelu
Tworzymy pierwszą klasę reprezentującą dane w bazie danych (menu projektu pod prawym klawiszem myszy, a stamtąd New->Entity Class...).
Nadajemy jej nazwę Pracownik w pakiecie (ponownie całkiem przypadkiem) pl.jaceklaskowski.
U dołu okna dialogowego ukaże się ostrzeżenie o braku tzw. Persistence Unit, czyli konfiguracji mechanizmu zapisu trwałego, co rozwiązujemy poprzez wybór przycisku Create Persistence Unit....
Tworzenie konfiguracji JPA
Jako pierwszy krok w konfiguracji JPA, NB wyświetli poniższe okno dialogowe, gdzie wybieramy jedyną pozycję na liście wartości w polu Database Connection.
i wciskamy przycisk Create.
Pojawi się okno dialogowe, które widzieliśmy poprzednio bez komunikatu o niedostępności konfiguracji JPA.
Wciskając przycisk Finish kończymy tworzenie klasy encyjnej - pl.jaceklaskowski.Pracownik, która jest uwieńczeniem procesu tworzenia modelu dla naszej aplikacji.
package pl.jaceklaskowski;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* Entity class Pracownik
*/
@Entity
public class Pracownik implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/** Creates a new instance of Pracownik */
public Pracownik() {
}
/**
* Gets the id of this Pracownik.
* @return the id
*/
public Long getId() {
return this.id;
}
/**
* Sets the id of this Pracownik to the specified value.
* @param id the new id
*/
public void setId(Long id) {
this.id = id;
}
/**
* Returns a hash code value for the object. This implementation computes
* a hash code value based on the id fields in this object.
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
int hash = 0;
hash += (this.getId() != null ? this.getId().hashCode() : 0);
return hash;
}
/**
* Determines whether another object is equal to this Pracownik. The result is
* <code>true</code> if and only if the argument is not null and is a Pracownik object that
* has the same id field values as this object.
* @param object the reference object with which to compare
* @return <code>true</code> if this object is the same as the argument;
* <code>false</code> otherwise.
*/
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Pracownik)) {
return false;
}
Pracownik other = (Pracownik)object;
if (this.getId() != other.getId() && (this.getId() == null || !this.getId().equals(other.getId()))) return false;
return true;
}
/**
* Returns a string representation of the object. This implementation constructs
* that representation based on the id fields.
* @return a string representation of the object.
*/
@Override
public String toString() {
return "pl.jaceklaskowski.Pracownik[id=" + getId() + "]";
}
}
W katalogu META-INF projektu powstanie plik o nazwie persistence.xml, który jest plikiem konfiguracyjnym JPA (podobnie jak hibernate.cfg.xml dla Hibernate, czy web.xml dla aplikacji internetowej).
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
<persistence-unit name="JpaStandalonePU" transaction-type="RESOURCE_LOCAL">
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<class>pl.jaceklaskowski.Pracownik</class>
<properties>
<property name="toplink.jdbc.url" value="jdbc:derby://localhost:1527/sample"/>
<property name="toplink.jdbc.user" value="app"/>
<property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="toplink.jdbc.password" value=""/>
<property name="toplink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
Modyfikacja klasy startowej aplikacji
Podczas utworzenia klasy encyjnej - pl.jaceklaskowski.Pracownik - uaktywniliśmy możliwość skorzystania z opcji Persistence w klasie głównej aplikacji - pl.jaceklaskowski.Main. Otwieramy ją i z menu pod prawym przyciskiem myszy wybieramy Persistence->Use Entity Manager.
Automatycznie dodane zostanie utworzenie klasy javax.persistence.EntityManagerFactory, która jest drzwiami wejściowymi do JPA oraz zostanie stworzona metoda do zapisu - persist. Dodajemy obsługę odczytu i wypełniamy treść metody main tak, że ostatecznie otrzymujemy gotową do uruchomienia klasę Main.
package pl.jaceklaskowski;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class Main {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("JpaStandalonePU");
public Main() {
}
public static void main(String[] args) {
if (args.length > 0) {
System.out.println("Pobrano " + new Main().findPracownik(Long.parseLong(args[0])));
return;
}
Pracownik p = new Pracownik();
new Main().persist(p);
System.out.println("Zapisano " + p);
}
public void persist(Object object) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
try {
em.persist(object);
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
} finally {
em.close();
}
}
public Pracownik findPracownik(long id) {
EntityManager em = emf.createEntityManager();
return em.find(Pracownik.class, id);
}
}
Uruchomienie aplikacji
Mamy już zdefiniowaną aplikację z odpowiednimi klasami - p.j.Main oraz p.j.Pracownik - i konfiguracją JPA - persistence.xml. Czas na jej uruchomienie. Zaznaczamy naszą aplikację w zakładce Projects i wybieramy menu Run Project pod prawym klawiszem myszy.
Pierwsze uruchomienie kończy się wyjątkiem.
Exception in thread "main" Local Exception Stack:
Exception [TOPLINK-4003] (Oracle TopLink Essentials - 2006.8 (Build 060830)): oracle.toplink.essentials.exceptions.DatabaseException
Exception Description: Configuration error. Class [org.apache.derby.jdbc.ClientDriver] not found.
at oracle.toplink.essentials.exceptions.DatabaseException.configurationErrorClassNotFound(DatabaseException.java:86)
at oracle.toplink.essentials.sessions.DefaultConnector.loadDriver(DefaultConnector.java:168)
at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:83)
at oracle.toplink.essentials.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:170)
at oracle.toplink.essentials.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:537)
at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:180)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:230)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:78)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:113)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:107)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:76)
at pl.jaceklaskowski.Main.persist(Main.java:25)
at pl.jaceklaskowski.Main.main(Main.java:20)
Po analizie wyjątku, stwierdzamy brak sterownika bazy danych (w końcu jest to sposób na nawiązanie połączenia z dowolną bazą danych w Javie i JPA skrzętnie z tego korzysta).
Dodajemy bibliotekę Java DB Driver do aplikacji (menu File->"JpaStandalone" Properties->Libraries->Run->Add Library)
Ponownie próbujemy uruchomić naszą aplikację. Tym razem pojawia się inny wyjątek.
Exception in thread "main" Local Exception Stack:
Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2006.8 (Build 060830)): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: org.apache.derby.client.am.DisconnectException: java.net.ConnectException : Error opening socket to server localhost on port 1527 with message : Connection refused: connectError Code: -4499
at oracle.toplink.essentials.exceptions.DatabaseException.sqlException(DatabaseException.java:289)
at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:87)
at oracle.toplink.essentials.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:170)
at oracle.toplink.essentials.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:537)
at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:180)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:230)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:78)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:113)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:107)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:76)
at pl.jaceklaskowski.Main.persist(Main.java:25)
at pl.jaceklaskowski.Main.main(Main.java:20)
Caused by: org.apache.derby.client.am.DisconnectException: java.net.ConnectException : Error opening socket to server localhost on port 1527 with message : Connection refused: connect
at org.apache.derby.client.net.NetAgent.<init>(Unknown Source)
at org.apache.derby.client.net.NetConnection.newAgent_(Unknown Source)
at org.apache.derby.client.am.Connection.<init>(Unknown Source)
at org.apache.derby.client.net.NetConnection.<init>(Unknown Source)
at org.apache.derby.jdbc.ClientDriver.connect(Unknown Source)
at java.sql.DriverManager.getConnection(DriverManager.java:525)
at java.sql.DriverManager.getConnection(DriverManager.java:140)
at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:85)
... 10 more
Co kieruje nas do zakładki Runtime i pozycji Databases, gdzie uruchamiamy naszą bazę danych - jdbc:derby://localhost:1527/sample [app on APP] za pomocą menu Connect (podajemy niepuste hasło, np. app).
Ponownie uruchamiamy naszą aplikację i ponownie wyjątek.
Exception in thread "main" Local Exception Stack:
Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2006.8 (Build 060830)): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: org.apache.derby.client.am.SqlException: password length, 0, is not allowed.Error Code: -99999
at oracle.toplink.essentials.exceptions.DatabaseException.sqlException(DatabaseException.java:289)
at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:87)
at oracle.toplink.essentials.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:170)
at oracle.toplink.essentials.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:537)
at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:180)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:230)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:78)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:113)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:107)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:76)
at pl.jaceklaskowski.Main.persist(Main.java:25)
at pl.jaceklaskowski.Main.main(Main.java:20)
Caused by: org.apache.derby.client.am.SqlException: password length, 0, is not allowed.
at org.apache.derby.client.net.NetConnection.checkPasswordLength(Unknown Source)
at org.apache.derby.client.net.NetConnection.checkUserPassword(Unknown Source)
at org.apache.derby.client.net.NetConnection.flowConnect(Unknown Source)
at org.apache.derby.client.net.NetConnection.<init>(Unknown Source)
at org.apache.derby.jdbc.ClientDriver.connect(Unknown Source)
at java.sql.DriverManager.getConnection(DriverManager.java:525)
at java.sql.DriverManager.getConnection(DriverManager.java:140)
at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:85)
... 10 more
Odgadnięcie, co jest przyczyną błędu jest już niezwykle proste i najważniejsze, że pozwala uwierzyć, że jesteśmy na dobrej drodze do uruchomienia naszej aplikacji. Naprawa sprowadza się do edycji pliku persistence.xml o wartość toplink.jdbc.password z hasłem, które wybralismy powyżej, np.
<property name="toplink.jdbc.password" value="app"/>
I ponowie przystępujemy do uruchomienia aplikacji (tym razem z nadzieją, że nie może być więcej mowy o wyjątkach).
[TopLink Config]: 2006.11.12 03:04:25.046--ServerSession(13205705)--The alias name for the entity class [class pl.jaceklaskowski.Pracownik] is being defaulted to: Pracownik.
[TopLink Config]: 2006.11.12 03:04:25.078--ServerSession(13205705)--The table name for entity [class pl.jaceklaskowski.Pracownik] is being defaulted to: PRACOWNIK.
[TopLink Config]: 2006.11.12 03:04:25.093--ServerSession(13205705)--The column name for element [private java.lang.Long pl.jaceklaskowski.Pracownik.id] is being defaulted to: ID.
[TopLink Info]: 2006.11.12 03:04:25.640--ServerSession(13205705)--TopLink, version: Oracle TopLink Essentials - 2006.8 (Build 060830)
[TopLink Config]: 2006.11.12 03:04:25.796--ServerSession(13205705)--Connection(17815542)--connecting(DatabaseLogin(
platform=>JavaDBPlatform
user name=> "app"
datasource URL=> "jdbc:derby://localhost:1527/sample"
))
[TopLink Config]: 2006.11.12 03:04:25.812--ServerSession(13205705)--Connection(23257749)--Connected: jdbc:derby://localhost:1527/sample
User: app
Database: Apache Derby Version: 10.1.3.1
Driver: Apache Derby Network Client JDBC Driver Version: 10.1.3.1
[TopLink Config]: 2006.11.12 03:04:25.812--ServerSession(13205705)--Connection(17423963)--connecting(DatabaseLogin(
platform=>JavaDBPlatform
user name=> "app"
datasource URL=> "jdbc:derby://localhost:1527/sample"
))
[TopLink Config]: 2006.11.12 03:04:25.812--ServerSession(13205705)--Connection(15020576)--Connected: jdbc:derby://localhost:1527/sample
User: app
Database: Apache Derby Version: 10.1.3.1
Driver: Apache Derby Network Client JDBC Driver Version: 10.1.3.1
[TopLink Config]: 2006.11.12 03:04:25.812--ServerSession(13205705)--Connection(20843194)--connecting(DatabaseLogin(
platform=>JavaDBPlatform
user name=> "app"
datasource URL=> "jdbc:derby://localhost:1527/sample"
))
[TopLink Config]: 2006.11.12 03:04:25.828--ServerSession(13205705)--Connection(3299256)--Connected: jdbc:derby://localhost:1527/sample
User: app
Database: Apache Derby Version: 10.1.3.1
Driver: Apache Derby Network Client JDBC Driver Version: 10.1.3.1
[TopLink Config]: 2006.11.12 03:04:25.828--ServerSession(13205705)--Connection(18687346)--connecting(DatabaseLogin(
platform=>JavaDBPlatform
user name=> "app"
datasource URL=> "jdbc:derby://localhost:1527/sample"
))
[TopLink Config]: 2006.11.12 03:04:25.843--ServerSession(13205705)--Connection(8755816)--Connected: jdbc:derby://localhost:1527/sample
User: app
Database: Apache Derby Version: 10.1.3.1
Driver: Apache Derby Network Client JDBC Driver Version: 10.1.3.1
[TopLink Config]: 2006.11.12 03:04:25.843--ServerSession(13205705)--Connection(22831804)--connecting(DatabaseLogin(
platform=>JavaDBPlatform
user name=> "app"
datasource URL=> "jdbc:derby://localhost:1527/sample"
))
[TopLink Config]: 2006.11.12 03:04:25.859--ServerSession(13205705)--Connection(5660886)--Connected: jdbc:derby://localhost:1527/sample
User: app
Database: Apache Derby Version: 10.1.3.1
Driver: Apache Derby Network Client JDBC Driver Version: 10.1.3.1
[TopLink Config]: 2006.11.12 03:04:25.859--ServerSession(13205705)--Connection(15696851)--connecting(DatabaseLogin(
platform=>JavaDBPlatform
user name=> "app"
datasource URL=> "jdbc:derby://localhost:1527/sample"
))
[TopLink Config]: 2006.11.12 03:04:25.859--ServerSession(13205705)--Connection(12039161)--Connected: jdbc:derby://localhost:1527/sample
User: app
Database: Apache Derby Version: 10.1.3.1
Driver: Apache Derby Network Client JDBC Driver Version: 10.1.3.1
[TopLink Config]: 2006.11.12 03:04:25.859--ServerSession(13205705)--Connection(8970080)--connecting(DatabaseLogin(
platform=>JavaDBPlatform
user name=> "app"
datasource URL=> "jdbc:derby://localhost:1527/sample"
))
[TopLink Config]: 2006.11.12 03:04:25.859--ServerSession(13205705)--Connection(78219)--Connected: jdbc:derby://localhost:1527/sample
User: app
Database: Apache Derby Version: 10.1.3.1
Driver: Apache Derby Network Client JDBC Driver Version: 10.1.3.1
[TopLink Info]: 2006.11.12 03:04:26.000--ServerSession(13205705)--file:/C:/projs/sandbox/JpaStandalone/build/classes-JpaStandalonePU login successful
Zapisano pl.jaceklaskowski.Pracownik[id=1]
Tym razem pomyślnie udało nam się uruchomić aplikację z JPA (opartym o Oracle TopLink). Gratulacje!
Kolejne uruchomienie skończyło się następującym komunikatem:
Zapisano pl.jaceklaskowski.Pracownik[id=51]
Pora na odszukanie stworzonych pracowników. Zaczynamy od pracownika o identyfikatorze 51 (w NB to menu Properties pod prawym klawiszem myszy i dalej Run, a tam pole Arguments, czyli 51).
Wciskamy przycisk OK i uruchamiamy nasz projekt. Ostatecznie otrzymujemy komunikat o pomyślnym odszukaniu pracownika:
Pobrano pl.jaceklaskowski.Pracownik[id=51]
I na tym kończymy nasze doświadczenia z JPA. Para NetBeans i Google spisała się dzisiaj na 5+! ;-)

