Prosty projekt dla Hibernate jako JPA2

W poprzednim wpisie poświęconym certyfikacji JPA wspominałem o tym, że dla nauki najbardziej wygodnym podejściem jest korzystanie z Hibernate w aplikacji konsolowej. Postanowiłem dla ułatwienia zamieścić bardzo prosty projekt (w oparciu o Mavena), aby pomóc w rozpoczęciu pracy.

Tworzymy w naszym IDE projekt Mavenowy. Grupy, artefakty i wersje pozostawiam już do swobodnej interpretacji. Najważniejsze są wszystkie zależności. Mój plik POM wygląda tak (zbudowany na podstawie jednego z przykładów dostępnych w sieci, nie pomnę juz skąd dokładnie):

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.wordpress.chlebik</groupId>
 <artifactId>jpa</artifactId>
 <version>1.0.0</version>
 <packaging>jar</packaging>

 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <maven.compiler.source>1.7</maven.compiler.source>
 <maven.compiler.target>1.7</maven.compiler.target>

 <hibernate.version>4.1.2.Final</hibernate.version>
 <org.apache.derby.version>10.8.1.2</org.apache.derby.version>

 <log4j.version>1.2.16</log4j.version>
 <slf4j.version>1.6.4</slf4j.version>

 </properties>

 <repositories>
 <!-- Hibernate Repository -->
 <repository>
 <id>jboss</id>
 <name>JBoss Release Maven Repository</name>
 <url>https://repository.jboss.org/nexus/content/repositories/releases/</url>
 </repository>
 </repositories>

 <pluginRepositories>
 <pluginRepository>
 <id>jboss-public-repository-group</id>
 <name>JBoss Public Maven Repository</name>
 <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
 <snapshots>
 <enabled>true</enabled>
 </snapshots>
 <releases>
 <enabled>false</enabled>
 </releases>
 </pluginRepository>
 </pluginRepositories>

 <dependencies>

 <dependency>
 <groupId>com.h2database</groupId>
 <artifactId>h2</artifactId>
 <version>1.2.145</version>
 </dependency>

 <dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-core</artifactId>
 <version>${hibernate.version}</version>
 </dependency>
 <dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-entitymanager</artifactId>
 <version>${hibernate.version}</version>
 </dependency>
 <dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-c3p0</artifactId>
 <version>${hibernate.version}</version>
 </dependency>
 <dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-ehcache</artifactId>
 <version>${hibernate.version}</version>
 </dependency>
 <dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-annotations</artifactId>
 <version>3.5.6-Final</version>
 </dependency>
 <dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-validator</artifactId>
 <version>4.2.0.Final</version>
 </dependency>

 <dependency>
 <groupId>log4j</groupId>
 <artifactId>log4j</artifactId>
 <version>${log4j.version}</version>
 </dependency>
 <dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-api</artifactId>
 <version>${slf4j.version}</version>
 </dependency>
 <dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>jcl-over-slf4j</artifactId>
 <version>${slf4j.version}</version>
 </dependency>
 <dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-log4j12</artifactId>
 <version>${slf4j.version}</version>
 </dependency>

 <dependency>
 <groupId>commons-lang</groupId>
 <artifactId>commons-lang</artifactId>
 <version>2.6</version>
 </dependency>
 </dependencies>

</project>

Do poprawnego działania potrzebujemy jeszcze dwóch rzeczy – persistence.xml oraz kodu (głównej klasy uruchamiającej oraz klasy domenowej). Zaczniemy od persistence.xml (w folderze /main/src/resources/META-INF).


<?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="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    
   <class>com.wordpress.chlebik.jpa.domain.Hero</class>
     
   <properties>
         <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
         <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE" />          
         <property name="javax.persistence.jdbc.user" value="sa" />
         <property name="javax.persistence.jdbc.password" value="" />

         <property name="hibernate.show_sql" value="true" />
         <property name="hibernate.hbm2ddl.auto" value="create" />
     </properties>
   
  </persistence-unit>
</persistence>


No i potem mamy klasę uruchomieniową:

package com.wordpress.chlebik.jpa;

import java.util.Date;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.wordpress.chlebik.jpa.domain.Hero;

public class App {
    
    public static void main(String... args) {

   EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "persistenceUnit" );
   EntityManager entityManager = entityManagerFactory.createEntityManager();

		entityManager.getTransaction().begin();
		Hero h = new Hero();
		h.setCreationDate(new Date());
		h.setLevel(1);
		h.setName("Chlebikowy Mag");
		entityManager.persist( h );

		entityManager.getTransaction().commit();
		entityManager.close();

    }
}

No i na koniec wspomniana klasa encji:

package com.wordpress.chlebik.jpa.domain;

import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table( name = "HEROES" )
public class Hero {

    @Id
    @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;

    @Temporal(TemporalType.TIMESTAMP)
    private Date creationDate;

    private String name;
    private Integer level;

    public Hero() { }

    // Gettery i settery ucięte

}

Taki prosty szkielet programu umożliwi nam pracę z JPA opierając się na bazie danych H2 uruchamianej w pamięci za każdym startem naszej aplikacji. Kompilacja i uruchomienie aplikacji trwa mgnienie oka, zaś dzięki Mavenowi bardzo łatwo jest ew. podmienić dostawcę JPA czy szybko przerobić projekt na appkę webową uruchamianą w kontenerze JEE.

Dla ułatwienia sobie prac i nauki można dorzucić jeszcze dwie rzeczy – logowanie oraz podgląd bazy danych. Logowanie dodać można bardzo prosto – do folderu /src/main/resources należy dodać plik log4j.properties, u mnie wygląda on tak:

log4j.rootLogger=WARN, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%n%m%n%n

I dzięki temu w naszej głównej klasie możemy sobie utworzyć obiekt loggera:

private static final Log log = LogFactory.getLog(App.class);

Dzięki czemu można obyć się bez System.out.println. Drugą sprawą jest baza danych i ew. podgląd jej zawartości. Zasadniczo przy używaniu JPA nie powinniśmy w ogóle dotykać bazy danych jako takiej. Jednakże jest to raczej pobożne życzenie – bardzo często JPA jest wprowadzane do istniejącego już schematu bazy. Do tego dobrze jest czasem popatrzeć czy aspekty wydajnościowe (klucze przede wszystkim) zostały poprawnie przez JPA rozpoznane. Tak jak pisałem w przypadku powyższej aplikacji baza danych jest przechowywana w pamięci i jako taka jest usuwana po zakończeniu działania programu. Czasem jednakoż dobrze byłoby przyjrzeć się wygenerowanym tabelom, relacjom czy zapisanym danym. Możemy to osiągnąć uruchamiając bazę H2 jako oddzieny proces w trybie serwerowym. By to osiągnąć trzeba oczywiście zaciągnąć plik JAR z bazą H2. Myślę, że strona domowa bazy jest świetnym miejscem by ten plik uzyskać. Po jego ściągnięciu na dysk trzeba plik JAR uruchomić (w Windowsie wystarczy na niego kliknąć). Pojawi się mniej więcej takie okienko.

H2Console

Odpowiednie pola trzeba wypełnić dokładnie takimi samymi wartościami jak powyżej. Po zrobieniu tego dajemy ‘Połącz’ i w przeglądarce mamy już dostęp do naszej bazy. Teraz wystarczy zmienić plik persistence.xml w miejscu dotyczącym połączenia.

<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1" />

I każdorazowe uruchomienie naszej aplikacji będzie łączyć się do bazy danych, ale stworzone tabele/relacje/dane zostaną zapisane i będą dostępne do przeglądania dopóki nie wyłączymy procesu H2. Oczywiście baza danych musi być odpalona 😉

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s