JAVA JPA WITH HIBERNATE AND H2 Tutorial

JAVA JPA WITH HIBERNATE AND H2 Tutorial

Setting the environment:

Download and install H2 Database
http://www.h2database.com/html/download.html

Create a connection to the database, in my case I am using Netbeans. Creation of a new Database Connection can be done from the Services Tab, Databases node:



Have in mind that it is not possible to test the connection before the JDBC URL has been written into. Select the PUBLIC schema when asked.

And put a name onto it, I decided to name it as "Hibernate 101 on H2"





Download Hibernate
http://sourceforge.net/projects/hibernate/files/hibernate3/

JPA with Hibernate:

For the shake of portability and standarization we will be using JPA. Natively speaking, Hibernate relies onto a context configuration file - hibernate.cfg - and a single or many persistence configuration files - hibernate.hbm.xml -.  On the other hand JPA configuration is based on just one file: persistence.xml. 
Netbeans offers us a wizard to create the corresponding persistence.xml file. Create the Hibernate101 project first and add the package com.ramontalavera.hibernate101. Right mouse button menu, new..., other,Persistence, Persistence Unit:


Now persistence.xml appears undet the META-INF.

Check that Hibernate libraries are present:


Remember to add the H2 driver jar to the libraries.

A simple bean to table mapping:

PersonDBO.class will be mapped to a table named "PERSONS". Note that no hibernate specific code will be used in this class, all annotations are taken from the javax.persistence package. Also take in mind that persistent classes should be Serializable.

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

The annotations @Entity and @Table let us map the class to the desired table, in our case "PERSONS".
@Entity
@Table( name = "PERSONS" )
public class PersonDBO implements Serializable {

The mapping annotations may be used in the properties section directly. ID fields use the @Id annotation. In this example we are associating an automatic sequence generator to the ID:

    @SequenceGenerator(name="PersonIdGenerator", sequenceName="PersonIdSequence")
    @Id
    @GeneratedValue(generator="PersonIdGenerator")
    private int id;

Properties are Mapped to columns with the @Column annotation:
    @Column(name = "SURNAME")
    private String surname;
    @Column(name = "FIRSTNAME")
    private String firstname;

Full class code follows:
package com.ramontalavera.hibernate101;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity
@Table( name = "PERSONS" )
public class PersonDBO implements Serializable {
  
    @SequenceGenerator(name="PersonIdGenerator", sequenceName="PersonIdSequence")
    @Id
    @GeneratedValue(generator="PersonIdGenerator")
    private int id;
    @Column(name = "SURNAME")
    private String surname;
    @Column(name = "FIRSTNAME")
    private String firstname;

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

        public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public int getId() {
        return id;
    }

   
}


Please, notice that setId was intentionally left out. JPA does not need the mutator to handle its database value, so not putting a setId method in your entities will protect them from being badly used during development. Changing the id of an entity is a very rare operation during business.


Hibernate101 Test:

Ok, ok, this test is written into a main, I know JUnit is cool, but this way the tutorial will be easier to follow by those not using JUnit.

To work with entities JPA provides an EntityManagerFactory that has to be inited with the desired PersistenceUnit (defined in persistence.xml), we named it Hibernate101PU.

public class Hibernate101 {
    private EntityManagerFactory entityManagerFactory;    
       
    public void init() throws Exception {
        setEntityManagerFactory(Persistence.createEntityManagerFactory( "Hibernate101PU" ));
    }

After initialising the EntityManagerFactory EntityManagers can be created and ordered to persist, update or delete our entities.

// Create an entity manager
        EntityManager entityManager=hibernate101.getEntityManagerFactory().createEntityManager();

Once the EntityManager is created transactions are begun by invoking:
// Begin a transaction
        entityManager.getTransaction().begin();
And commited with the commit method. Usually a flush is forced before commiting:
//Flush and commit the transaction
 entityManager.flush();
 entityManager.getTransaction().commit();

To perform a persistence of the entity:
// Persist a person
            entityManager.persist(person);
This persistence should be in between the creation and commit of the transaction, of course.

When the EntityManager is no longer needed , a call to close should be done, same applies to EntityManagerFactory.

package com.ramontalavera.hibernate101;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;


public class Hibernate101 {
    private EntityManagerFactory entityManagerFactory;
    
    public Hibernate101()
    {
        
    }
    
    public void init() throws Exception {
        setEntityManagerFactory(Persistence.createEntityManagerFactory( "Hibernate101PU" ));
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        Hibernate101 hibernate101=new Hibernate101();
        
        hibernate101.init();
        
        PersonDBO person= new PersonDBO();
        person.setSurname("Ramon");
        person.setFirstname("Talavera");
        
        // Create an entity manager
        EntityManager entityManager=hibernate101.getEntityManagerFactory().createEntityManager();
        // Begin a transaction
        entityManager.getTransaction().begin();
        // Persist a person
            entityManager.persist(person);
        //Flush and commit the transaction
        entityManager.flush();
        entityManager.getTransaction().commit();
        
        //Close the entity manager and the factory
        entityManager.close();
        hibernate101.getEntityManagerFactory().close();
    }

    public EntityManagerFactory getEntityManagerFactory() {
        return entityManagerFactory;
    }

    public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
        this.entityManagerFactory = entityManagerFactory;
    }
}


Inform about the new persistence class in persistence.xml:
Even if not needed at this point, informing about this Entity class in persistence.xml will result helpful when including OneToMany or ManyToMany relationships:



<?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="Hibernate101PU" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.ramontalavera.hibernate101.PersonDBO</class>
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/Hibernate101;AUTO_SERVER=TRUE"/>
      <property name="javax.persistence.jdbc.password" value="12345"/>
      <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
      <property name="javax.persistence.jdbc.user" value="sa"/>
      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
    </properties>
  </persistence-unit>
</persistence>


Choosing the Table Generation Strategy:
During testing it is sometimes useful to recreate the database from scratch every time the test is run, that can be chosen in persistence.xml, just select "Drop and Create" to achieve this effect.




Run the example and check H2 console for Hibernate101 database, the table PERSONS and new data should be present now.

Same can be done under Netbeans/Services tab:


What if I want to see the SQL queries that are being used?

Just add <property name="hibernate.show_sql" value="true"/>  to the properties section of persistence.xml. Generated SQL Queries will be shown during execution.


General Queries with Where Clauses:

Using JPQL:



public CarRegistrationPlate getPlate(String numbers,String letters) throws NotFoundException
    {
        List<CarRegistrationPlate> found = new ArrayList();
        Query query = entityManager.createQuery(
        "FROM CarRegistrationPlate WHERE Numbers=:arg1 and Letters=:arg2");
        query.setParameter("arg1", numbers );
        query.setParameter("arg2", letters );
        found = (List<CarRegistrationPlate>) query.getResultList();
        if (found.isEmpty())
            throw new NotFoundException();
        return found.get(0);
    }


Using Java EE 6's JPA 2.0


public CarRegistrationPlate getPlate(String numbers,String letters) throws NotFoundException
    {
        CriteriaBuilder cb = _entityManager.getCriteriaBuilder();
        CriteriaQuery<CarRegistrationPlate> query = cb.createQuery(CarRegistrationPlate.class);
        Root<CarRegistrationPlate> sm = query.from(CarRegistrationPlate.class);
        query.where(
                cb.and(
                    cb.equal(sm.get("numbers"), versionName),
                    cb.equal(sm.get("letters"), buildName) 
                    )
                );
        found = (List<CarRegistrationPlate>) entityManager.createQuery(query).getResultList();
        if (found.isEmpty())
            return null;
        return found.get(0);
    }


Multiple unique keys:

@Entity
@Table( name = "CARREGISTRATIONPLATES", 
        uniqueConstraints={ 
                        @UniqueConstraint(columnNames = {"numbers", "letters"})
                        }
        )
    
public class CarRegistrationPlate implements IPersistible {

        
    @SequenceGenerator(name="CarRegistrationPlateIdGenerator", sequenceName="CarRegistrationPlateIdSequence")
    @Id
    @GeneratedValue(generator="CarRegistrationPlateIdGenerator")
    private int id;
    
    @Column(name = "NUMBERS",nullable = false)
    private String numbers;
    @Column(name = "LETTERS",nullable = false)
    private String letters;
    // gets sets follow...
 }







Comments

Popular posts from this blog

Qt Signals and Slots, Connecting and Disconnecting

Vaadin 7: Detect Enter Key in a TextField