Sunday, April 12, 2009

Hibernate Annotations & EntityManager With JPA and Spring

Hibernate is an Open Source Object Relational mapping tool which provides transparent persistence for POJOs. Object-relational mapping is used to map object-oriented programming objects to relational databases managed by Oracle, DB2, Sybase, and other relational database managers (RDBMSs)

Hibernate allows you to express queries in its own portable SQL extension (HQL), as well as in native SQL, or with an object-oriented Criteria.

Other popular ORM solutions are iBatis, JDO and TopLink.

JPA(Java Persistence API)

Java Persistence API was included as part of the Java EE 5 platform. This new API simplifies the development of Java EE and Java SE applications using data persistence. This also gets the entire Java community behind a single, standard persistence API.The Java Persistence API draws upon the best ideas from persistence technologies such as Hibernate, TopLink, and JDO.

Hibernate implements the Java Persistence object/relational mapping and persistence management interfaces with the Hibernate Annotations and Hibernate EntityManager modules, on top of the mature and powerful Hibernate Core.

Since JPA's are used for persistence in the application the ORM providers can be easily changed, in the below example it is easy to replace Hibernate with TopLink , since it will be only configuration changes. This is because we have used JPA's in our entity classes and used entitymanager and we have not stuck to any hibernate specific API's

Hibernate Annotations

Hibernate, like all other object/relational mapping tools, requires metadata that governs the transformation of data from one representation to the other (and vice versa). As an option, you can now use JDK 5.0 annotations for object/relational mapping with Hibernate 3.2. You can use annotations in addition to or as a replacement of XML mapping metadata.

You can use Hibernate extension annotations on top of standardized Java Persistence annotations to utilize all native Hibernate features.

Hence in all the below sample entities you can use of javax.persistence.* classes which are the JPA's used to indicate hibernate about the mapping it has to perform in the Database.

In the basic format of hibernate without annotations,we need to define the mapping between between a class and the Db tables using hibernate config files.

Hibernate EntityManager

It implements:

* The standard Java Persistence management API
* The standard Java Persistence Query Language
* The standard Java Persistence object lifecycle rules
* The standard Java Persistence configuration and packaging

Hibernate EntityManager wraps the powerful and mature Hibernate Core. You can fall back to Hibernate native APIs, native SQL,and native JDBC whenever necessary.

Spring For Hibernate

When used with hibernate this reduces a lot of work like obtaining session for each and every transaction .Instead we mention this using @Transaction annotation that the entitymanger needs to be transaction enabled and spring takes care of managing the session using
AOP.Spring also helps in easy configuraion of the DB and ORM into the entitymanager.

Now since we are familiar with the technologies to be used lets build a sample application

Configuration in spring.xml

Assuming we use mysql as the DB following will be the configuration.

Declaring the Datasource

<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/<DB_NAME>" />
<property name="username" value="<USER_NAME>" />
<property name="password" value="<PASSWORD>" />
</bean>


BeanPostProcessor that processes PersistenceUnit and PersistenceContext annotations, for injection of the corresponding JPA resources EntityManagerFactory and EntityManager. Any such annotated fields or methods in any Spring-managed object will automatically be injected.

This post-processor will inject sub-interfaces of EntityManagerFactory and EntityManager if the annotated fields or methods are declared as such.

PersistenceAnnotationBeanPostProcessor only supports @PersistenceUnit and @PersistenceContext

<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

This creates a JPA EntityManagerFactory according to JPA's standard container bootstrap contract. This is the most powerful way to set up a shared JPA EntityManagerFactory in a Spring application context

As with LocalEntityManagerFactoryBean, configuration settings are usually read in from a META-INF/persistence.xml config file, residing in the class path, according to the general JPA configuration contract.

The datasource is given as a parameter to the ORM(hibernate) which later if given as a parameter to JPA factory to create the entitymanager.

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>


This defines a transaction manager which is responsible for opening and closing sessions when an entity manager is used.

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>


This ensures that session management for all classes/methods marked with @Transactional are taken care by the transaction manager, that is it will take care of opening the sessions and closing them.

<tx:annotation-driven transaction-manager="transactionManager" />

This is a directive to spring to enable annotations.

<context:annotation-config/>

JPA configuration

1. Create a folder named "META-INF" under the "src" folder.
2. Create a file named "persistence.xml" under the "META-INF" folder and set its content to:

persistence.xml

<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_1_0.xsd"
version="1.0">
<persistence-unit name="punit">
</persistence-unit>
</persistence>

Now lets create a sample class in Java(Class mapping to DB table)

package test;

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

@Entity
@Table(name = "T_STUDENT")
public class Student {
@Id
@GeneratedValue
@Column(name = "F_ID")
private Integer id;
private String lastName;
private String firstName;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}
}

in the above class

@Entity indicates that this class will be mapped to a table in database

@Table indicates the corresponding table name in DB , if this is not mentioned the default class name will be taken

@Id Indicates the primary key to the table

@GeneratedValue - Indicates the strategy used to generate primary key for the table

@Column - indicates the corresponding column name for the filed in the DB.


Now Lets write a service to access these

Interface

package test;

import java.util.List;

public interface IStudentService {

public List<Student> findAll();

public void save(Student student);

public void remove(int id);

public Student find(int id);
}


Implementation

package test;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.transaction.annotation.Transactional;


@Transactional
public class StudentService implements IStudentService {


private EntityManager em;

//This is injected by spring
@PersistenceContext
public void setEntityManager(EntityManager em) {
this.em = em;
}


//gets all the student tuples from the DB
@SuppressWarnings("unchecked")
public List<Student> findAll() {
Query query = getEntityManager().createQuery("select s FROM Student s");
return query.getResultList();
}


//saves a touple int DB , if its already exists will update it
public void save(Student student) {
if (student.getId() == null) {
// new
em.persist(student);
} else {
// update
em.merge(student);
}
}

//deletes a touple from teh DB
public void remove(int id) {
Student student = find(id);
if (person != null) {
em.remove(student);
}
}

private EntityManager getEntityManager() {
return em;
}

//gets a tuple based on the primarykey
public Student find(int id) {
return em.find(Student.class, id);
}

}


Now the above service can be injected using spring to any action class and used to do all the required DB operations.

4 comments:

Martin said...

Hello, thank you for your article. I have one question related to JpaTransactionManager. I am using JpaTransactionManager as a transactionManager and some DB errors(e.g. PacketTooBig exception ...) arent propagated back into our Service class but ends on proxy - JpaTransactionManager - so our aplication crash. How i can catch all possible exceptions from JpaTransactionManager ?

Sudheer Krishna said...

Did u use @SuppressWarnings annotation to suppress the warning s in ur service classes ?

Martin said...

Only find* methods use annotation @SuppressWarnings ("unchecked"). But my problem is on create/update methods. I am using @Transactional annotation (thats JpaTransactionManager).

Sudheer Krishna said...

i am afraid i do not have an answer now.

 
Free Domain Names @ .co.nr!