Saturday, 18 August 2012

Standalone Hibernate JPA In-Memory Example

This post describes an hibernate/JPA example in a standalone application (no application server or container required). It is available from Github, in the Standalone-Hibernate-JPA directory.

The purpose is to activate Hibernate with an in-memory database instance and illustrate basic CRUD (Create, Read, Update, Delete) operations. We use a simple JPA annotated item and Pojomatic for a nice string representation:
@Entity
@AutoProperty
public class Item implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long ID;

    // Setter & Getters, Pojomatic methods...

}
The CRUD operations are:
public static void save(Object o) {
    EntityTransaction et = EM.getTransaction();
    et.begin();
    EM.persist(o);
    et.commit();
}

public static <T> T get(Class<T> entityType, Object key) {
    return EM.find(entityType, key);
}

public static void update(Object o) {
    EntityTransaction et = EM.getTransaction();
    et.begin();
    EM.merge(o);
    et.commit();
}

public static void delete(Object o) {
    EntityTransaction et = EM.getTransaction();
    et.begin();
    EM.remove(o);
    et.commit();
}
The following:
private static EntityManagerFactory EMF;
private static EntityManager EM;

public static void main(String[] args) {

    // Creating resources
    EMF = Persistence.createEntityManagerFactory("Standalone");
    EM = EMF.createEntityManager();

    // Create
    Item i = new Item();
    i.setName("Item A");
    System.out.println("Before saving   : " + i);
    save(i);
    System.out.println("After saving    : " + i);

    // Read
    Item retr = get(Item.class, i.getID());
    System.out.println("Retrieved I     : " + retr);

    // Update
    i.setName("Item B");
    System.out.println("Updated         : " + i);
    update(i);
    retr = get(Item.class, i.getID());
    System.out.println("Retrieved II    : " + retr);

    // Delete
    System.out.println("Deleting        : " + i);
    delete(i);
    retr = get(Item.class, i.getID());
    System.out.println("Retrieved III   : " + retr);

    // Closing resources
    EM.close();
    EMF.close();

}
Generates the following output:
Before saving   : Item{ID: {0}, name: {Item A}}
After saving    : Item{ID: {1}, name: {Item A}}
Retrieved I     : {1}, name: {Item A}}
Updated         : Item{ID: {1}, name: {Item B}}
Retrieved II    : Item{ID: {1}, name: {Item B}}
Deleting        : Item{ID: {1}, name: {Item B}}
Retrieved III   : null
Notice that the id value is set after saving.

REM: The way transactions are used in the above example is not clean. Typically, one should wrap them in a try catch as following to trigger rollbacks when necessary:
EntityTransaction et = EM.getTransaction();
try {
    et.begin();
    EM.merge(o); // Or any other operations...
    et.commit();
} catch(Exception ex) {
    et.rollback();
    throw ex;
}

The Web Application version of this example is available here. More about JPA transaction types and the Java Transaction API (JTA) here.

--------------------

The persistence.xml file is configured as following (with hsqldb):
<persistence 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" version="2.0">

    <persistence-unit name="Standalone" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>com.jverstry.standalone.Item</class>
        <properties>
          <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
          <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:testdb"/>
          <property name="javax.persistence.jdbc.user" value="sa"/>
          <property name="javax.persistence.jdbc.password" value=""/>
          <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
          <property name="hibernate.hbm2ddl.auto" value="create"/>
        </properties>

    </persistence-unit>

</persistence>
The dependencies are:
<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>2.2.8</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>4.1.5.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>4.1.5.Final</version>
</dependency>
<dependency>
    <groupId>org.pojomatic</groupId>
    <artifactId>pojomatic</artifactId>
    <version>1.0</version>
<type>jar</type>
</dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.6</version>
</dependency>
<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>6.0</version>
    <type>jar</type>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.0.0.GA</version>
    <scope>test</scope>
</dependency>