SlideShare una empresa de Scribd logo
1 de 80
Object Relationship Mapping (ORM)



  ORM stands for Object relational Mapping. ORM is an attempt to map the notion of object and

  relational world so that they can talk to each other in a easy way. Any non trivial application has a

  database behind it and Java applications are no exception. In fact if we look closely into any

  application, one will realize that the application gets more or less modeled around the data model. In

  database technology, relational database are the clear winners. Other database technologies has come

  and gone. Relational concept of data management was first introduced by E.F. Codd in 1970. An

  analogy for relational model can be drawn with spreadsheets. Each sheet represents a table and the

  columns in the sheet represent the table attributes. Each instance of data is represented by the rows.

  The data in different sheets are connected with each other by referring to the data point using the

  sheet number, column number and row number. This is what is called as foreign key relationship in

  database technology. In fact most of the GUI interfaces to database show the data in a spreadsheet

  format.

  To interact with the database, Standard Query Language(SQL) has emerged as the standard way. The

  SQL standards are controlled by ANSI. However there are still proprietary variations to it. SQL

  provides two types of mechanism:


Data Definition Language (DDL) : Provides ways to create and alter tables.

Data Manipulation Language (DML) : Provides ways to manipulate and retrieve data. It includes

inserting, updating and deleting data.

  To interact with the database, the applications has to issue SQL to the database. How to issue SQL is

  proprietary to each database. They have their own API's exposed for this and the API's might be

  written in different languages. For example a database written in C language. might expose C based

  API's. Considering that the data independence is considered a virtue for any application, it would be a

  lot of work for an application developer to understand the interfaces for each of the database and

  implement it. To solve this kind of porblem, Java has come up with ((JDBC)) API's.


  JDBC is the most popular way of connecting to databases in Java. It's an interface based API where

  the implementation for each database is provided by the drivers for particular database. Though JDBC

  is very popular, it is inherently relational in nature. The basic problem is the mismatch in conceptual

  level between relational technology and Object Oriented Technology. Java being a pure Object
Oriented Language, this mismatch is important to deal with. This mismatch is also known as Object

relational mismatch. ORM tries to solve this mismatch.


Let's see the kind of mismatch that are there:


Inheritance


Java supports inheritance. For example we might have User class from which Student and Teacher

class is derived.

User


public class User{

private String Name;


//Setters and getters

}


Student


public class Student extends User{

private double percentage;



//Setter and Getter

}


Teacher


public class Teacher extends User{

private int exprienceYears;


//Setters and Getters

}


Now think for a moment how you are going to map these classes to the table structure. ORM

frameworks adopt different strategies to solve this, which can be seen at ((Hibernate)) section.
Also with this comes the mismatch in terms of polymorphism. A reference of User type can refer to an

object of Student or Teacher. Also a list might contain a mix of Teacher, Student and User objects.

How you build those list by querying database. The ORM frameworks has to somehow differentiate

that the data is belonging to User or Student or Teacher.


Granularity


The granularity problem comes when the number of classes mapping to number of tables in the

database do not match. For example let's say we have the User class which has an Address object


public class User{

private String Name;

private Address address;


//Setters and getters

}


Address


public class Address{

private String city;

private String country;


//Setters and getters


Also the table structure for User is


Table USER:


NAME

CITY

COUNTRY


There is one table but the data is sitting in two objects. The same problem can come the other way

round also where you have two tables and one class containing all the data points. ORM frameworks

has to care of this mismatch in terms of different number of tables mapped to different number of

classes.
Identity and Equality


The notion of identity is driven by primary key in relational model. Given a primary key you will always

retrieve the same data. Also it does not matter, how many clients are retrieving the same data. With

right isolation level all will see the same data. In Java the situation becomes more complex. The same

data row might be represented by more objects in Java layer. For example a User data in database

with primary key 1 might have more than one object in different thread. The question comes which is

the object having the right data. Also if all thread try to save the same object, than who wins? Similar

problem arises related to equality. In Java the default is reference equality. If the references are

pointing to the same object than they are equal. The corollary is that if there are two objects

representing the same data row, they will come out as different. To solve this we have to give

implementation to the equals methos, but it's not always trivial. ORM solutions has to provide

provisions to maintain the correct notion of equality and identity. The frameworks usually ask to

explicitly map the primary key to an attribute.


Association


In Java the relationship is done by association. For example User has a reference of address. However

in Tables, the relationship is done with foreign key association. Java has also the notion of

directionality. For example you can access address form User but not the other way round. To build

the relationship from both side you have to put the reference on both the sides.

User


public class User{

private Address address;



//Setters and Getters

}


Address


public class Address{

private User user;


//setters and getters

}
However there is no notion of directionality in the relational world.The foreign key relationship can be

done at any one end and the relationship is build. With SQL you can navigate from any end. For

example the foreign key relationship build at User side will be


Table ADDRESS


ADDRESS_ID

CITY

COUNTRY


Table USER


USER_ID

NAME

ADDRESS_ID (Fk)


ORM solutions has to deal with these association while setting and getting the data from the database.


Type Systems


Object Oriented and relational world has different type systems. For example in relational world string

can be constrained on the size however on the Java side you can point the reference of String to any

size based on memory allocated. Also date and times are handled differently in Java and relational

world. For example in some databases there is a distinction between date, time and timestamp. Time

stamp contains both date and time. In Java, the date is a long value which contains the date and time

both. So when you fetch the date or time from relational world how you map it to a Java data type of

Date or Calendar.


Databases are Different


There are so many popular databases in the market. In spite of SQL being a standard, there are still

variations in the SQL support in each database and there are many vendor extensions and individual

flavors in each database. Though this is not really an ORM issue but it is important from the

perspective of database portability, if you are looking for it. Ensuing database portability using JDBC is

usually a hurricane task if you wish to use the individual flavors of database for performance or other

reasons. ORM frameworks attempt to handle most of the important databases transparently. Also they

do have extension mechanisms if you wish to support another database
A video explaining the above concepts:


  ORM frameworks adopt different strategies to solve these kind of mismatches. ORM frameworks strive

  to preserve the notion of object world concepts and shield the developers from relational world by

  taking care of mappings. This should be taken as an excuse to not to learn relational concepts. In fact

  on the other way to be a good user of ORM frameworks, one should understand how the mapping

  works and the implications of it. The number issue in using ORM frameworks is performance and most

  of the time its because of not understanding how the ORM frameworks map to the relational world and

  not having a good grasp of relational world concepts.




                    Hibernate Introduction



  Hibernate is an ORM framework. It provides capability to interact with database in an object oriented

  way. Hibernate provides its own HQL (Hibernate query language) also. The concepts of ORM are now

  adopted in EJB3.0 in the form of entity beans and Jave Persistence API (JPA). Hibernate supports

  Entity beans also. This means hibernate can act as an implementation provider for Entity beans. In

  fact, JBoss uses hibernate as implementation provider for Entity beans. Hibernate has its own set of

  API's also which at the moment are richer than JPA. Going forward however we might see Entity beans

  and JPA closing this gap.


  Let's make a Java project where we will persist the data into the database. First download the

  Hibernate Core from https://www.hibernate.org/6.html. Unzip the download at a location and you will

  find the following important directories/file in it (This might be different from what you see as

  hibernate keeps on changing the structure).


doc - contains the reference document for hibernate

eg - example application

etc - configuration files

grammer

lib - contains dependencies for hibernate. See lib/_README.txt for details about libraries.

src - source code of hibernate

test - test suite
hibernate3.jar - hibernate library

  Make a simple Java application in your IDE. Have the following libraries in the build path:

  From Hibernate Core (<hibernate-distribution-*>/lib/required)


antlr-2.7.6

commons-collections-3.1.jar

dom4j-1.6.1.jar

javassist-3.9.0.GA.jar

jta-1.1.jar

slf4j-api-1.5.8.jar

<hibernate-distribution-*>/lib/ -Choose between cglib or javassist

<hibernate-distribution>/*hibernate3.jar

  Download slf4j from http://www.slf4j.org/dist/


slf4j-simple-1.5.8.jar

hsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar.

  Hibernate is a Object relational mapping framework. What it will help us is in saving the objects into

  the relational world. So let's have our Java class whose object instances at runtime will be saved by

  hibernate to the database.


  public class Student {



  //Id will correspond the primary key in the database

  private Long id;

  protected String name;



  public Long getId() { return id; }


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


  public String getName() {return name;}


  public void setName(String name) {this.name = name;}

  }
Now we have the domain class definition with us. Now we will put a mapping file which will map this

class to the data model in the database. We are not creating the table in the database as we will use

hibernate to generate the data model. Though in real life application you would have your data model

already created and placed in the database.

Student.hbm.xml (Put it together with Student class)


<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


<hibernate-mapping>

<!-- class attributes -

name - Java class name

table - Table to which this class is mapped

schema - The schema where it sits

id -

name - name of property on Java class. It will result in getId() and setId method

column - column in table to which it is mapped

generator- how the id's to be generated

-->

<class name="com.oyejava.Student" table="Student" schema="PUBLIC">

<id name="id" column="STUDENT_ID">

<generator class="increment"/>

</id>



<!-- name - name of property in Java class. getName() and setName()

column - column in table to which it is mapped. -->

<property name="name" column="NAME" />

</class>

</hibernate-mapping>


Now we will provide hibernate the details to connect to the database. Similar to JDBC coding, the

connection details and drivers need to be provided to Hibernate. We will use hsql, the details of which
can be seen at HypersonicThis is done in a XML file.

hibernate.cfg.xml (Put it in the class path)


<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">


<hibernate-configuration>

<session-factory>

<!-- Database connection settings -->


<!-- If the below drive does not works try org.hsqldb.jdbc.JDBCDriver-->

<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>

<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>

<property name="connection.username">sa</property>

<property name="connection.password"></property>


<!-- JDBC connection pool (use the built-in) -->

<property name="connection.pool_size">1</property>


<!-- SQL dialect - This tells the SQL grammer to be used -->

<property name="dialect">org.hibernate.dialect.HSQLDialect</property>


<!-- Enable Hibernate's automatic session context management -->

<property name="current_session_context_class">thread</property>


<!-- Disable the second-level cache -->

<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>


<!-- Log out all the sql that hibernate is issuing to datbase.

This is very useful for debugging -->

<property name="show_sql">true</property>


<!-- Create the table looking at class and mapping. Very useful in development

Use validate in production environments. -->

<property name="hbm2ddl.auto">create</property>
<!-- Mapping file. -->

<mapping resource="com/oyejava/Student.hbm.xml"/>

</session-factory>

</hibernate-configuration>


Now we will write a utility class which will start the session factory of hibernate, if it is not started and

will return the Session factory. This is the most used pattern of boot strapping Hibernate. Session

factory contains all the configuration information at runtime. A Session is retrieve from the Session

factory. A session is a light weight object which provide services to interact with database. You can

think of Session like JDBC connection, thought it may not open the database connection if not

required.

HibernateUtil


public class HibernateUtil {



private static SessionFactory sessionFactory;



static{

try{

//By default it will look for hibernate.cfg.xml in the class path

sessionFactory=new Configuration().configure().buildSessionFactory();

}catch(Throwable ex){

throw new ExceptionInInitializerError(ex);

}

}



public static SessionFactory getSessionFactory(){

return sessionFactory;

}



public static void shutdown(){

//Close caches and connection pool

getSessionFactory().close();

}
}

Now let's write the main class in which we will create a Student object and persist it to database


public class HibernateBasic {


public static void main(String[] args) {


//Get the session from the Session factory

Session session = HibernateUtil.getSessionFactory().openSession();



Transaction tx= session.beginTransaction();



Student student = new Student();

student.setName("oyeJava");



Long studentId = (Long)session.save(student);



System.out.println(studentId);



tx.commit();

session.close();

}

}


Run the application and check in the database. It should persist a row of data. Download the source

code from down below in the attachment section. The libraries has to be included as per the list given

above.


In the above example we saw how to configure hibernate using XML mapping. The present trend is

however to move towards annotation based mapping.
Hibernate Introduction with Annotation

  Before Java 5, Hibernate has XML way of configuring things. However with introduction of

  Annotations, the world has changed a lot. Many frameworks has adopted annotations as an alternative

  to XML. Hibernate has also adopted annotation. The XML way is still supported but annotation is the

  predominant way of working now. We will do the same example as we did in Hibernate Introduction

  using annotation.


  Download the Hibernate Core and Hibernate Annotations from https://www.hibernate.org/6.html.

  Let's make a Java project and pull the following libraries.

  From Hibernate Core (<hibernate-distribution-*>/lib/required)


antlr-2.7.6

common-collections-3.1.jar

dom4j-1.6.1.jar

hibernate3.jar

javassist-3.9.0.GA.jar

jta-1.1.jar

slf4j-api-1.5.8.jar

<hibernate-distribution-*>/lib/ -Choose between cglib or javassist

  From Hibernate Annotation:


lib/ejb3-persistence.jar

lib/hibernate-commons-annotations.jar

hibernate-annotations.jar

  Download slf4j from http://www.slf4j.org/


slf4j-simple-1.5.8.jar

  Hypersonic:


hsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar.

For details see ((Hypersonic)).
Now let's write our domain class which is Student class.

Student


//Entity annotation represents that it is an entity class and is

//mapped to a table in database. Table annotation tells about the

//table name to which this entity is mapped

@Entity

@Table(name="Student")

public class Student {



//Id will correspond the primary key in the database

private Long id;

protected String name;



//Id - Represents that it is a primary key column

//GeneratedValue - How the key to be generated

//column - Column to which this property is mapped

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

@Column(name="STUDENT_ID")

public Long getId() {

return id;

}



public void setId(Long id) {

this.id = id;

}



//There is annotation here so by default it is mapped to

//the column with name NAME. In annotation, the properties are

//by default mapped. In XML mapping by default the columns

//are not mapped.

public String getName() {

return name;

}
public void setName(String name) {

this.name = name;

}

}


If you have done the Hibernate Introduction, you will realize that the mapping has been pulled in the

class file itself in terms of annotations. The parallel can easily be drawn. Also now we do not need any

mapping hbm.xml file. We still need the configuration XML, though the mapping will be done by

referencing to class

hibernate.cfg.xml (Put it in the class path)


<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">


<hibernate-configuration>

<session-factory>

<!-- Database connection settings -->

<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>

<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>

<property name="connection.username">sa</property>

<property name="connection.password"></property>


<!-- JDBC connection pool (use the built-in) -->

<property name="connection.pool_size">1</property>


<!-- SQL dialect - This tells the SQL grammer to be used -->

<property name="dialect">org.hibernate.dialect.HSQLDialect</property>


<!-- Enable Hibernate's automatic session context management -->

<property name="current_session_context_class">thread</property>


<!-- Disable the second-level cache -->

<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Log out all the sql that hibernate is issuing to datbase.

This is very useful for debugging -->

<property name="show_sql">true</property>


<!-- validates the table structure as per mapping definition. -->

<property name="hbm2ddl.auto">validate</property>


<!-- Mapping class. -->

<mapping class="com.oyejava.Student"/>

</session-factory>

</hibernate-configuration>


Let's write the Hibernate util class which is a utility class to make the Hibernate session factory. The

Session factory at runtime contains all the configuration and mapping details. From Session factory we

can get the Session, which is a lightweight object and helps us in interacting with the database.

Session can be thought of as a Connection as in JDBC thought the Session may choose to not to open

the connection to the database.

HibernateUtil


public class HibernateUtil {



private static SessionFactory sessionFactory;



static{

try{

//By default it will look for hibernate.cfg.xml in the class path

sessionFactory=new

AnnotationConfiguration().configure().buildSessionFactory();

}catch(Throwable ex){

throw new ExceptionInInitializerError(ex);

}

}



public static SessionFactory getSessionFactory(){

return sessionFactory;

}
public static void shutdown(){

//Close caches and connection pool

getSessionFactory().close();

}


}


Now in the application logic, in this case in the main method we can create a Student object and save

it to the database.



public class HibernateBasic {


public static void main(String[] args) {


//Get the session from the Session factory

Session session = HibernateUtil.getSessionFactory().openSession();



Transaction tx= session.beginTransaction();



Student student = new Student();

student.setName("oyeJava");



Long studentId = (Long)session.save(student);



System.out.println(studentId);



tx.commit();

session.close();

}

}


Those who have done the hibernate in the XML way will notice that the only difference the two has got

is in terms of where the mapping is kept. You can download the source code from the attachment

section down below.
Hibernate For Entity Beans of EJB



  Hibernate also support Entity beans and Java Persistence Provider(JPA) of EJB3.0+ specification. In

  fact many of the concepts of Entity beans has been taken from Hibernate. JBoss application server

  uses Hibernate as the default persistence provider for Entity beans and JPA. JPA has the notion of

  persistence unit which represents the configuration.

  EntityManagerFactory of JPA corresponds to SessionFactory and EntityManager corresponds to

  Session. Let's do the ((Hibernate Introduction with Annotation)) example of persisting Student object

  using Entity beans and JPA API's


  Download the Hibernate Core, Hibernate Annotations and Hibernate EntityManager from

  https://www.hibernate.org/6.html . Let's make a Java project and pull the following libraries.


  From Hibernate Core (<hibernate-distribution-*>/lib/required)


antlr-2.7.6

commons-collections-3.1.jar

dom4j-1.6.1.jar

hibernate3.jar

javassist-3.9.0.GA.jar

jta-1.1.jar

slf4j-api-1.5.8.jar

<hibernate-distribution-*>/lib/ -Choose between cglib or javassist

  From Hibernate Annotation:


lib/ejb3-persistence.jar

lib/hibernate-commons-annotations.jar

hibernate-annotations.jar

  From Hibernate Entity Manager:


lib/jboss-archive-browsing.jar

hibernate-entitymanager.jar
Download slf4j from http://www.slf4j.org/


slf4j-simple-1.5.8.jar

  Hypersonic:


hsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar.

For details see ((Hypersonic)).

  Now let's write our domain class which is Student class.Note that it the same class as we did in

  ((Hibernate Introduction with Annotation))

  Student


  //Entity annotation represents that it is an entity class and is

  //mapped to a table in database. Table annotation tells about the

  //table name to which this entity is mapped

  @Entity

  @Table(name="Student")

  public class Student {



  //Id will correspond the primary key in the database

  private Long id;

  protected String name;



  //Id - Represents that it is a primary key column

  //GeneratedValue - How the key to be generated

  //column - Column to which this property is mapped

  @Id

  @GeneratedValue(strategy = GenerationType.AUTO)

  @Column(name="STUDENT_ID")

  public Long getId() {

  return id;

  }



  public void setId(Long id) {

  this.id = id;

  }
//There is annotation here so by default it is mapped to

//the column with name NAME. In annotation, the properties are

//by default mapped. In XML mapping by default the columns

//are not mapped.

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}


Now let's write persistence.xml. This is the configuration file that EJB mandates. It is similar to what

hibernate configuration file does. It can support multiple persistence provider other than hibernate

also.

persistence.xml (Put in META-INF folder under source folder)


<?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">

<!-- This name is used to refer to this persistence context.

This will be used while we make the EntityManagerFactory -->

<persistence-unit name="hibernateMapping">

<!-- Persistence provider -->

<provider>org.hibernate.ejb.HibernatePersistence</provider>

<!-- Provide properites of persistence provider. This is

specific to each persistence provider. All hibernate related properties

which sit in hibernate.cfg.xml can be put here. -->

<properties>

<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>

<property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost"/>
<property name="hibernate.connection.username" value="sa"/>

<property name="hibernate.connection.password" value=""/>

</properties>

</persistence-unit>

</persistence>


Now we just have to write our main class and start interacting with database.


public class HibernateMappingJPA {


public static void main(String[] args) {

//The name hibernateMapping comes from persistence.xml

EntityManagerFactory emf =

Persistence.createEntityManagerFactory("hibernateMapping");



//EntityManager is similar to Session in hibernate

EntityManager em = emf.createEntityManager();

EntityTransaction tx = em.getTransaction();

tx.begin();



Student student = new Student();

student.setName("James Bond");

em.persist(student);



//Query API

Query query = em.createQuery("Select s from Student s where s.name like ?");

query.setParameter(1, "James%");

List<Student> studentList = query.getResultList();

for(Student s :studentList){

System.out.println(s.getName());

}



tx.commit();

em.close();
}

}


Note that we do not have to map the entity class explicitly as these are scanned automatically based

on the @Entity annotation. The source code can be downloaded from the attachment section down

below.


Hibernate Concepts



Entity and Value Type


Hibernate makes distinction between entity and value types. Entity types represent the objects that

can be persisted to the database. They are the first class citizen in hibernate. Hibernate manages the

life cycle of and entity. An entity also has an identifier which identifies the different instances uniquely.

Value types are objects which are managed in the context of an entity. They live and die within the

scope of an entity. This distinction comes because of Hibernate philosophy of promoting rich domain

model. This means more classes per table. Let's say we have Student Table which contains the

Address also


Student table

ID

NAME

CITY

COUNTRY


Now we can map this table to two class. One Entity and another value type

Student (entity class)


@Entity

public class Student{

private Long id;

private String name;

private Address address;
//Setters and getters


  Address (value class)


  public class Address{

  private String city;

  private String country;


  //setters and getters

  }


  So we have got two classes for one table. Also the life of Address object is within the life scope of

  Student object.The Student object can live independently but an independent address object has no

  meaning unless it is associated with a Student object.


  Flushing


  Flushing is the process of propagating the changes from the Java layer to the database. Whenever the

  call is done for a save, hibernate does not issues the SQL automatically. It keeps on noting the

  changes and queues all the SQL. The SQL's are issued to database at appropriate time. This

  propagation of changes is known as flushing. The default mode for flushing is automatic, where

  hibernate identifies when to flush. The flushing is done in the following cases:


When the transaction is committed.

Before query execution so that the query sees the latest data in the database.

When session.flush() is called explicitly.

  The flushing mode can be changed by calling session.setFlushMode with parameter

  FlushMode.COMMIT. In this case the flushing happens only


When the transaction is committed.

When session.flush() is called explicitly.

  Dirty Checking


  Hibernate automatically tracks the changes in the entities when they are in managed state and

  persists the changes to the database. Look at the following example
//Get the session from the Session factory. In the first unit of work we persist the Student object

Session session = HibernateUtil.getSessionFactory().openSession();

Transaction tx= session.beginTransaction();



Student student = new Student();

student.setName("oyeJava");



Long studentId = (Long)session.save(student);



tx.commit();

session.close();



//Start another unit of work. Note that we fetch the same row that we have saved.

//Now change the name of student object but do not call any save or update method.

//Still hibernate will figure out that the object has changed and hibernate will

//persist the changes to the datbase.The process of finding the changes is known as dirty checking

also.

session = HibernateUtil.getSessionFactory().openSession();

tx= session.beginTransaction();



Student student1 = (Student)session.get(Student.class, studentId);

student1.setName("Again Java");



tx.commit();

session.close();


Whenever hibernate fetches or saves an object to the database, it keeps a snapshot of the object. At

the point when hibernate goes to persist the changes, it loops through all the objects and matches it

with the snapshot it has got.If it identifies that the state of an entity has changed from its snapshot it

flushes those changes to the database.


Hibernate Debugging
Debugging Hibernate application tends to be tricky as there is a time lag between application issuing a

calls on hibernate api and hibernate issuing SQL to the database.We will look into various strategies to

look into how to debug hibernate.


Configuration


Enable show_sql property in the hibernate configuration file. In your hibernate.cfg,xml put the

following


<!-- Log out all the sql that hibernate is issuing to datbase.

This is very useful for debugging -->

<property name="show_sql">true</property>


This will flush all the sql that hibernate issues to databae. For example in ((Hibernate Introduction

with Annotation)) example you will see in the console


Hibernate: insert into Student (STUDENT_ID, name) values (null, ?)


Enable format_sql to format the generate sql. However this will take more space. Change in

hibernate.cfg.xml


<!-- Format the logged sql -->

<property name="format_sql">true</property>


In the console


Hibernate:

insert

into

Student

(STUDENT_ID, name)

values

(null, ?)


To understand the origin of SQL, hibernate can put comments which can be enabled by putting the

following property in hibernate.cfg.xml
<!-- Show comment -->

  <property name="use_sql_comments">true</property>


  In the console

  Hibernate:

  /* insert com.oyejava.Student */

  insert

  into

  Student

  (STUDENT_ID, name)

  values

  (null, ?)


  Enabling log4j


  Enabling logging level in log4j.properties can provide more information about the internal of

  application. Copy the sample log4j.properties from hibernate core download at etc folder. Run the

  application and you will tons of information about internals of hibernate. Tweak the level in

  log4j.properties. Enabling log4j.logger.org.hibernate.type at debug level will show the bind

  parameters. Do the following in log4j.properties. The following line is already there, you have to

  uncomment it.


  log4j.logger.org.hibernate.type=TRACE


  In the console


  Hibernate: insert into Student (STUDENT_ID, name) values (null, ?)

  16:04:15,440 DEBUG StringType:133 - binding 'oyeJava' to parameter: 1


  Debugging Source


  The hibernate download comes with the source code. The src folder in the download has all the

  source. For hard to solve problems you can start digging into the source code itself. In eclipse you can

  do it as follows:


Go to Project properties by right clicking on project name in navigator view and than click on Properties.

Go to Java Build Path -> Source
Click on Link Source

In the Linked Folder location and pick the location of hibernate source till src

In the folder name give a name which does not conflicts with your present source location.

Click on Finish and than Ok. You can now put break point in the application and can go the hibernate

code.


  Hibernate Tools

  Hibernate tool comes as an eclipse plugin. This has useful feature including HQL editor which helps in

  development. To install Hibernate Tool follow the steps :


Check as per your eclipse version, the right version of tool at http://www.jboss.org/tools/download.html

. You can either download or use the update mechanism. (Update mechanism is better if you are the

only one. If you want to share it among the team members go via download mechanism.) I will follow

the download mechanism to show the steps.

Extract the download zip file. There will be two folders features and plugins. Copy the files inside features

into eclipse/features. Similarly do for plugins.

If eclipse is up, close it and restart.

In eclipse click on Window->Open Perspective->Other.

Click on hibernate. It will open the hibernate perspective.


  Hibernate Mapping Class

  The basic notion of ORM is mapping between class and table. A class is considered to be an entity

  when it gets the Entity annotation.


  Entity


  @Entity

  public class Student {


  We can provide a name to an entity. By default the name is the class name. We can give another

  name to entity so that conflicts do not occur because of same name entity sitting in different package


  @Entity(name="anotherStudent")

  public class Student {
By default this entity gets mapped to a table with same name. If we want to specify the table name

explicitly


@Entity

@Table(name="Student")

public class Student {


Dynamic SQL Generation


Hibernate by default generates the SQL for CRUD right in the beginning. This also means that even if

we just update one property of the entity, still the update is issued for all the properties. If we want

hibernate to generate SQL at runtime only taking care of changed entity only than use Entity

annotation coming from hibernate.


Let's introduce a property in Student class age


@Entity

@Table(name="Student")

public class Student {



//Id will correspond the primary key in the database

private Long id;

protected String name;

protected Integer age;



//Getters and Setters

...

public Integer getAge() {

return age;

}


public void setAge(Integer age) {

this.age = age;

}

...
Persist the student by making a new Student object and setting show_sql true.


Student student = new Student();

student.setName("oyeJava");

Long studentId = (Long)session.save(student);


The SQL generated by hibernate as seen in console is


insert into Student (STUDENT_ID, age, name) values (null, ?, ?)


Note that though the age has not been set but still the SQL contains the age parameter. Now let's

introduce the Entity annotation from Hibernate so that we ask hibernate to generate the SQL at

runtime rather than using the pre generated CRUD statement


//dynamicInsert - Include only those properties which are not null in inserting the data

//dynamicUpdate - Include only those properties which have changed

@Entity

@org.hibernate.annotations.Entity(

dynamicInsert=true,

dynamicUpdate=true)

public class Student {


The SQL generated at console is


insert into Student (name, STUDENT_ID) values (?, null)


Note that the age field is absent. This is useful when the table has very large number of columns and

modification and insertion is done only on smaller number of columns.


Immutability


When we know that an entity is not going to change at runtime. For example older messages fetched

from database, than we can ask hibernate to not to do dirty checking for it. This also results in better

performance.


@org.hibernate.annotations.Entity(

dynamicInsert=true,
dynamicUpdate=true,

mutable=false

)

public class Student {



Hibernate Mapping Identity

Identity of an object is the property which is mapped to primary key of the row in the database. The id

of the entity is mapped by @Id annotation


@Entity

@Table(name="Student")

public class Student {



//Id will correspond the primary key in the database

private Long id;

protected String name;



...


//Id - Represents that it is a primary key column

//GeneratedValue - How the key to be generated

//column - Column to which this property is mapped

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

@Column(name="STUDENT_ID")

public Long getId() {

return id;

}



public void setId(Long id) {

this.id = id;

}

...


Hibernate supports many identifier generation strategy which supports all the major databases
Hibernate does not allows to change the Id once it has been set. It throws an exception if an attempt

is made


student = new Student();

Long studentId = (Long)session.save(student);

//student.setId(80L); - This will throw an exception


Right now JPA supports limited identifier generation strategy. So if the hibernate generation strategies

need to be employed than do as follows:


@Entity

@org.hibernate.annotations.GenericGenerator(

name="hibernate-native",

strategy="native")

public class Student{



private Long id;

protected String name;



@Id

@GeneratedValue(generator="hibernate-native")

@Column(name="STUDENT_ID")

public Long getId() {

return id;

}


It's possible to write one's own identifier generation strategy by implementing IdentifierGenerator

interface. However try to use one of the existing generator as Hibernate already has very rich

identifier generators.



Hibernate Mapping Properties

In this section we will look into how to map the different types of properties. All properties if mapped

with annotation are by default persistent. This is different from when XML is used for mapping. In XML

mapping, only the properties explicitly mapped are persistent.
Transient


  If a property needs to be stopped from being persistent.


  @Transient

  public int getActive() {

  return active;

  }


  Now this property does not becomes part of persistent mechanism. The property resides only in the

  Java layer.


  Temporal


  Allow to map java.util.Date and java.util.Calender. In SQL the date are differentiated by whether it's a

  date, time or a timestamp. Timestamp has both date and time. However in Java the date is always a

  timestamp. It has all the information. So we have to deal with this mismatch also.


  //Options for TemporalType

  // - DATE

  // - TIME

  // - TIMESTAMP

  @Temporal(TemporalType.TIMESTAMP)

  public Date getBirthDate() {

  return birthDate;

  }


  Large Data


  Large data is characterized by whether it is a binary large data (BLOB) or character larger date (CLOB)


Blob - byte[], Byte[]

Clob - char[], Character[]

  BLOB and CLOB both are mapped with Lob annotation


  @Lob

  public byte[] getPicture() {
return picture;

}


Enumeration


Enumeration are type safe way of restricting the choice in Java. Let's say we have enum defined in

Java as


public enum StudentType {

CURRENT,

ALUMNI

}


to specify the usage of this enum in entity


@Enumerated(EnumType.STRING)

public StudentType getStudentType() {

return studentType;

}


Enum Type can be String or Ordinal. If String is specified, in the database CURRENT or ALUMNI is

stored. If ordinal is specified 0 or 1 is saved. If Enum Type is omitted ORDINAL is taken as default.


Derived Properties


Derived properties are useful to calculate formulas or derived values which is not stored in database

but important for business purpose.


@org.hibernate.annotations.Formula("(MARKS/TOTAL_MARKS)*100")

public Long getPercentage() {

return percentage

}


The value is evaluated while fetching the entity so it might be outdated at other times. It's the

responsibility of the developer to keep it updated.The property appears in the SELECT statement only

and does not participates in INSERT or UPDATE statement.Even SQL expression can be passed to the
underlying database so there is a chance to build database dependency.SQL functions including SQL

subselects can be used.


Handling Generated Values


In DDL we define defaults to many values like SYSDATE for timestamp which means if we do not give

value from Java it is automatically generated.After saving if we want to refresh the object in Java

layer, we will have to call a refresh on the object. The other way is that we can tell Hibernate to

refresh the value automatically after an insertion. Make sure that you have dynamicInsert set to false

otherwise null value will be inserted into the database.


@Column(updatable= false, insertable = false)

@org.hibernate.annotations.Generated

(org.hibernate.annotations.GenerationTime.INSERT)

public Double getPendingAmount() {

return pendingAmount;

}


Embedded classes


Embedded classes are useful for bringing fine domain modeling. We have one table but more classes

mapped to it to bring rich domain model. Though Student table contains all the details for Student and

his address, we will map it to two classes.


Student Table


Student_Id

Name

City

Country


Let's have city and country mapped to a different class Address. We put Embeddable annotation on it

to tell that it will be used as an embedded property in an entity class


@Embeddable

public class Address {

protected String city;
protected String country;



@Column(name = "ADD_CITY")

public String getCity() {


In the Student class


private Address address;

@Embedded

public Address getAddress() {

return address;

}

//Setter method


By default this will mapped to ADD_CITY column name as mapped in Address. To get it mapped to

CITY column as in Student table, we ill have to override the column name.



@Embedded

@AttributeOverride (name= "city",column = @Column(name="CITY"))

public Address getAddress() {

return address;

}


Now in this case we can navigate to Address object by holding a reference of Student object. But it's

not possible to navigate from Address object to Student object. To build the bi directional navigation in

Address entity

In Address class



@org.hibernate.annotations.Parent

public Student getStudent() {

return student;

}


public void setStudent(Student student) {

this.student = student;

}
Hibernate Collection Mapping

  Hibernate supports collection mapping as value type. In Hibernate collection mapping, the collection

  are mapped into a separate table but are not exposed as entity on the Java side. Hibernate supports

  following collection interfaces as value type:


java.util.Set – java.util.HashSet is used to store value.

java.util.SortedSet – java.util.TreeSet is used to store value.

java.util.List – java.util.ArrayList is used to store value. Preserves the position with an index column

Bag semantics – java.util.ArrayList is used to store valre however the position is not preserved.

java.util.Map – java.util.HashMap is used to store value.

java.util.SortedMap – java.util.TreeMap is used to store value.

  Let‟s say we want to store Phones for a Student. There are more than one Phone for a Student. So we

  will have two tables corresponding to Student and Phone. However we do not want to expose Phone


  Table STUDENT


  STUDENT_ID

  ...


  Table PHONE


  STUDENT_ID

  NUMBER

  ...


  STUDENT_ID is the foreign key and PHONE table has no primary key. To map the Phone collection as

  a Set in the Student Entity class


  Student class


  ...

  @org.hibernate.annotations.CollectionOfElements(targetElement = java.lang.String.class)

  @JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))

  @Column(name="PHONE_NO")
public Set<String> getPhones() {

...


The lifecycle of Phone is tightly coupled to Student. Also Phone table is not exposed as an entity. If the

Set need to be sorted


...

@org.hibernate.annotations.CollectionOfElements(targetElement = java.lang.String.class)

@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))

@Column(name="PHONE_NO")

@org.hibernate.annotations.Sort(type=org.hibernate.annotations.SortType.NATURAL)

public Set<String> getPhones() {

...


A comparator can also be used for Sort type.


To map the Phone collection as a list


...

@org.hibernate.annotations.CollectionOfElements

@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))

@org.hibernate.annotations.IndexColumn(name=“INDEX_POSITION", base =1)

@Column(name="PHONE_NO")

public List<String> getPhones() {

return phones;

}

---


Here the index is mapped to a INDEX_POSITION column in the table and preserves the ordering. If

the index is not given, this works like a Bag. Bag is a list but does not preserves the position.


To map Phone as a map where PHONE_NAME will act as key and PHONE_NO as value from the PHONE

table. To map it


...

@org.hibernate.annotations.CollectionOfElements

@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))
@org.hibernate.annotations.MapKey(columns = @Column(name="PHONE_NAME"))

@Column(name="PHONE_NO")

public Map<String,String> getPhones() {

...


Here the Phone table is mapped directly as a collection. We can also expose Phone as a value object.

In this case define Phone as a class


@Embeddable

public class PhoneValue {



protected Student student;

protected String name;

protected String phoneNumber;



@org.hibernate.annotations.Parent

public Student getStudent() {

return student;

}

...


Also in the above case we maintain a back pointer for Student so that we can navigate from Phone to

Student. To define the collection of embedded object in Student class


...

protected Collection<PhoneValue> phoneValues = new ArrayList<PhoneValue>();


@org.hibernate.annotations.CollectionOfElements

@JoinTable(name = "Student_Phone_Value",joinColumns = @JoinColumn(name="STUDENT_ID"))

@CollectionId(columns= @Column(name="STUDENT_PHONE_VALUE_ID"),

type=@org.hibernate.annotations.Type(type="long"),

generator="sequence")

public Collection<PhoneValue> getPhoneValues() {

return phoneValues;

}

...
Hibernate collection mapping is a way of mapping the collection table as values. The lifecycle of the

 the collections are tightly bound to the collection of the owning entity.


 Hibernate Relationship Mapping

 Hibernate relationship mapping takes care of mapping the relationship in the relational world. The

 relationship that exist in the relational world are:


@OneToOne

@OneToMany

@ManyToOne

@ManyToMany

 Though the notion of directionality is not present in relational world, it is relevant for the Java world.

 So we will have to handle in the Java world whether we want to build unidirectional or bidirectional

 relation. Please note the the need of unidirectional or bidirectional relationship should be governed by

 your need of domain. For example if we have a Student and Address table with One to One

 relationship between them.


 One To One


 Let's say we have Address and Student in its own table and we expose Address also as an entity.


 @Entity

 public class AddressEntity implements Serializable{

 protected Long id;

 ….

 @Id

 @GeneratedValue

 @Column(name="ADDRESS_ID")

 public Long getId() {

 return id;

 }


 Map the relationship in the Student entity with directionality build from Student side

 In Student class
...

private AddressEntity address;


//Cascade Type defines that if the owning entity in this case Student is saved, than

//whether the AddressEntity will also get saved.

@OneToOne(cascade={CascadeType.ALL})

@JoinColumn(name="ADDRESS_ID")

public AddressEntity getAddressEntity() {

return address;

}

...


Also note the cascade type here. The cascade type defines whether the AddressEntity will get saved

when we save Student. For example let's say the mapping in Student class, if we remove the Cascade

type will be:


...

private AddressEntity address;


@OneToOne // comment out - (cascade={CascadeType.ALL})

@JoinColumn(name="ADDRESS_ID")

public AddressEntity getAddressEntity() {

return address;

}

...


Now let's try to save a Student and AddressEntity


Student student = new Student();

AddressEntity add = new AddressEntity();

student.setAddressEntity(add);


//If you try to save student, it will throw an exception as

//it finds AddressEntity wired to it but AddressEntity is transient.

//To persist the transient AddressEntity with the Student uncomment the CascadeType

//session.save(student);
We can make the primary key for both the related table same. It means that in the Address table the

primary key and foreign key are same.

In the Student class


@OneToOne(cascade={CascadeType.ALL})

@PrimaryKeyJoinColumn

public AddressEntity getAddressEntity() {

return addressEntity;

}


In the above case the AddressEntity can be reached from Student but from AddressEntity you cannot

reach to Student. Map the Student entity in the AddressEntity class


...

protected Student student;


@OneToOne(mappedBy="bankAccount")

public Student getStudent() { return student; }

...


Note that this relationship in the Java world does not makes any change to the relational world.


In the case of bidirectional association, there is a notion of owning entity. The owning entity governs

in what case the relationship will materialized in the database.The owning entity is the entity which is

on the opposite or inverse side of mappedBy. In the case as the mappedBy is on the AddressEntity,

the Student entity becomes the owning type. Now look at following piece of code


Student student = new Student();

AddressEntity add = new AddressEntity();


//Map the relationship from AddressEntity side

add.setStudent(student);


//we will assume that CascadeType is All.

session.save(student);
If we look into the database, the Student and AddressEntity both are created in the database but the

  relationship is not build between Student and AddressEntity table. To fix the problem change the

  above code to


  Student student = new Student();

  AddressEntity add = new AddressEntity();


  //Map the relationship from Student side

  student.setAddressEntity(add);


  //we will assume that CascadeType is All.

  session.save(student);


  Now the relationship will be properly created as we have made the relationship from owning side. It's

  a good price to build the relationship from both side whenever the relationship is effected from one

  side.


  Student student = new Student();

  AddressEntity add = new AddressEntity();


  //Good Practice: Map the relationship on both side

  student.setAddressEntity(add);

  add.setStudent(student);


  //we will assume that CascadeType is All.

  session.save(student);


  For owning entity, you have to take care of following:


If a AddressEntity has to be assigned to a different student, than unset the addressEntity on the original

student and set it into the new student.

For deleting a AddressEntity, unset it from the student object and than remove it from database calling

remove method on entity manager.

  One To Many


  Let's have PhoneEntity table with one to Many relationship from Student.
Student Table


STUDENT_ID //Primary Key

...


PhoneEntity table


PHONE_ID //Primary Key

STUDENT_ID //Foreign Key

...


Now the PhoneEntity class looks like


@Entity

public class PhoneEntity implements Serializable{

protected int id;

protected String number;


@Id

@GeneratedValue

@Column(name="PHONE_ID")

public int getId() {


There is no reference to Student in PhoneEntity class, though the relationship is maintained in

PhoneEntity table in database. Now to build the One to Many relationship in Student


@OneToMany(cascade={CascadeType.ALL})

public Collection<PhoneEntity> getPhoneEntityList() {

return phoneEntityList;

}


To save phone Entity the code would look like


Collection<PhoneEntity> phoneList = new ArrayList<PhoneEntity>();

PhoneEntity p1 = new PhoneEntity();

p1.setNumber("100");

phoneList.add(p1);
PhoneEntity p2 = new PhoneEntity();

p2.setNumber("200");

phoneList.add(p2);


student.setPhoneEntityList(phoneList);


We can tell hibernate that if an element is removed from a collection than delete it from database as

this is the only reference to that entity.


@OneToMany(cascade={CascadeType.ALL})

@org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN

)

public Collection<PhoneEntity> getPhoneEntityList() {

return phoneEntityList;

}



If we want the relationship data to be managed in a join table


@OneToMany(cascade={CascadeType.ALL})

@JoinTable(name="STUDENT_PHONE",joinColumns={@JoinColumn(name="STUDENT_ID")},

inverseJoinColumns={@JoinColumn(name="PHONE_ID")})

public Collection<PhoneEntity> getPhoneEntityList() {

return phoneEntityList;

}


Now let's see Many To One unidirectional relationship. Let's say we have a country table and Student

is mapped to Country with Many to One relationship.


Student Table


STUDENT_ID //Primary Key

COUNTRY_ID //foreign Key

...


Country Table
COUNTRY_ID //Primary Key

...


Country Entity


@Entity

public class Country implements Serializable{

protected long id;

protected String name;


@Id

@GeneratedValue

@Column(name="COUNTRY_ID")

public long getId() {

return id;

}

...


Student Entity


private Country country;

@ManyToOne

@JoinColumn(name="COUNTRY_ID")

public Country getCountry() {

return country;

}


Note that we are not using cascade here as normally the country is a master data and should not be

created or deleted in the context of a Student. To save a Student


Country country = new Country();

country.setName("India");

session.save(country);

student.setCountry(country);


Many to one and One to many are two sides of the same relationship. Let‟s convert Student and

Country into bidirectional relationship.
//the owning side of relationship is Many To One

@OneToMany(mappedBy="country")

public Collection<Student> getStudentList() {

return studentList;

}



For persistence to work we have to call student.setCountry. If we just call

country.getStudentList().add(student), The relationship will not change in the database. As a good

practice


Always wire both side of relationship.


Many To Many


ManyToMany relationship happens when both side maintains collection based relationship.Let‟s take

an example of Student and Language they speak. A student can speak many language. Similarly a

language can be spoken by many students

Language Entity bean


@Entity

public class Language implements Serializable{

protected long id;

protected String name;


Student Bean


@ManyToMany

@JoinTable(name=“A_B",joinColumns={@JoinColumn(name=“C")},

inverseJoinColumns={@JoinColumn(name=“D")})

public Collection<Language> getLanguageList() {

return languageList;

}


For Many to Many bidirectional

Language Bean
@ManyToMany(mappedBy="languageList")

  public Collection<Student> getStudentList() {

  return studentList;

  }


  For modifying the same ownership rule applies as we have seen in other bidirectional relationships.

  The collection can be fetched in certain order. E.g if we want to fetch the list of languages in certain

  order we can say on the Student side of relationship


  @ManyToMany

  @OrderBy(“name ASC”)

  @JoinTable(name="STUDENT_LANGUAGE",

  joinColumns={@JoinColumn(name="STUDENT_ID")},

  inverseJoinColumns={@JoinColumn(name="LANGUAGE_ID")})

  public List<Language> getLanguageList() {

  return languageList;

  }


  For descending order use name=DESC


  Hibernate Mapping Inheritance

  Inheritance is an important concept in Java but there is no counterpart in Relational world. There are

  some solutions is relational world but they are not widely used and also vendor specific. Hibernate

  provide some strategies to handle this situation where the inheritance hierarchy is mapped into the

  relational world.


  Let's have the java classes where we have a User class and Employee and Customer are inherited

  from it. The various strategies employed by hibernate to map this hierarchy to relational world is as

  follows:


Single Table per class hierarchy – Single table has all properties of every class in the hierarchy.

Table per concrete class – Each subclass has a table having all the properties of super class also.

Table per subclass – Each class is mapped in its own table. There is separate table for super class and

subclass.Table

  Single Table per class hierarchy
In Single table per subclass, the union of all the properties from the inheritance hierarchy is mapped

to one table. As all the data goes in one table, a discriminator is used to differentiate between

different type of data.


User (Base classe)


//DiscriminatorColumn - Tells about the type of data

//DiscriminatorValue - Is the data is representing User type, the value is "USER"

@Entity

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)

@DiscriminatorColumn(name="DISCRIMINATOR", discriminatorType=DiscriminatorType.STRING)

@DiscriminatorValue("USER")

@Table(name="BASIC_USER")

public class User{



protected long id;

protected String name;


Customer class


//There is no id column

@Entity

@DiscriminatorValue("CUST")

public class Customer extends User{

protected double creditLimit;


Employee class


//There is no id column

@Entity

@DiscriminatorValue("EMP")

public class Employee extends User{

protected String rank

...

}
The table structure would look like


  Basic_User Table


  ID

  NAME

  CREDIT_LIMIT

  RANK

  DISCRIMINATOR


  Now the objects can be saved polymorphically


  //User object referred by User type reference

  User user = new User();

  user.setName("Superman");

  session.save(user);



  Customer customer = new Customer();

  customer.setName("Spiderman");

  customer.setCreditLimit(1060);

  //User reference pointing to Customer object

  User user2 = customer;

  session.save(user2);


  Advantages of Single Table per class hierarchy


Simplest to implement.

Only one table to deal with.

Performance wise better than all strategies because no joins or sub-selects need to be performed.

  Disadvantages:


Most of the column of table are nullable so the NOT NULL constraint cannot be applied.

Tables are not normalized.

  Table per concrete class
In this case let's say our User class is abstract and Customer and Employee are concrete classes. So

  the table structure that comes out is basically one table for Customer and one table for Employee. The

  data for User is duplicated in both the tables. The User entity in this case is


  User


  @Entity

  @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)

  public abstract class User{

  protected long id;

  protected String name;


  @Id

  @GeneratedValue(strategy = GenerationType.AUTO)

  public long getId() {



  ...


  Customer class


  @Entity

  public class Customer extends User{

  protected double creditLimit;

  ...


  This strategy is not popular and also have been made optional in Java Persistence API.

  Advantage:


Possible to define NOT NULL constraints on the table.

  Disadvantage:


Tables are not normalized.

To support polymorphism either container has to do multiple trips to database or use SQL UNION kind of

feature.

  Table per Sub class
In this case all the classes are mapped to its own table. It's highly normalized but performance is not

good.


User class


@Entity

@Inheritance(strategy=InheritanceType.JOINED)

@Table(name="BASIC_USER")

public class User implements Serializable{



protected long id;

protected String name;

...

}


Employee class


@Entity

@PrimaryKeyJoinColumn(name="EMPLOYEE_ID")

public class Employee extends User{



protected String rank;

...

}


The derived class mapped table contain the foreign key which maps it to the base class. The table

structure is as follows


Basic_User Table


ID

NAME


Employee table


EMPLOYEE_ID // Acts both as primary key and foreign key.

RANK
Advantage:


Tables are normalized.

Able to define NOT NULL constraint.

  Disadvantage:


Does not perform as well as SINGLE_TABLE strategy

  A comparison of three strategies is as follows:



                                                                                            Table per
  Criteria           Single Table                   Table per subclass
                                                                                            concrete class



                                                                                             One table for
                         Data not normalized.
                                                                                             each concrete
                         Constraint for
                                                                                             class.
                         mandatory columns to
                                                     Normalized.                             Not maintainable.
                         be not nullable cannot
  Table Support                                      Mandatory column constraint             Change in base
                         applied.
                                                     can be applied                          class leads to
                         Change in any subclass
                                                                                             changes in all
                         leads to change in
                                                                                             tables of derived
                         structure of Table
                                                                                             class


  Discriminator
                     Present                        Absent                                  Absent
  Column

                                                    Joins among table. For example
                     simple SELECT. All data
                                                    fetching Customer will require a
                     is in one table. Using
  Retrieving                                        join on Customer and User table.        Separate Select or
                     discriminator type,
  data                                              If all user needs to be fetched         Union Select
                     individual types can be
                                                    than it will put a join for all three
                     selected
                                                    tables

                                                    Multiple. For User type one insert      One insert or
  Updating and       Single INSERT or
                                                    on User table. For Customer type        update for each
  Inserting          UPDATE
                                                    one insert on User table and            subclass
another on Customer table.

  JPA Support          Mandatory                 Optional


  Which Strategy to Choose


  Usually the choice is between Single Table and Table per subclass strategy. Table per concrete class is

  optional in JPA and may hinder your portability later on.They also represent the two ends of the

  spectrum. Some rule of thumbs are:


If there are many properties common in the base class and very less uncommon properties in derived

class. Go for Single table strategy. However make sure your database architect is comfortable with

nullable constraint not put on the properties of derived class. If there are too many uncommon

properties, you might want to go for table per subclass strategy.

Another criteria is the amount of polymorphic queries you do. If most of the time you fetch Customer

and Employees separately you can go for Table per subclass as this will involve join only on two tables a

time. However if you have requirements where you fetch User polymorphically most of the time, Single

table strategy will give better performance.

  Inheriting From a non entity base class


  Let's say we want to put Audit information in many tables. We can make Audit as a base class and

  make our entities class to inherit from Audit class


  Audit class


  @MappedSuperclass

  public class Audit {



  protected Date updateDate;

  protected Date createDate;


  @Temporal(TemporalType.TIMESTAMP)

  public Date getCreateDate() {

  return createDate;

  }
...

}


User class


@Entity

@Table(name="BASIC_USER")

//If we want to overried the column name than AttributeOverride is required

@AttributeOverride(name="createDate",column=@Column(name="CREATE_DATE"))

public class User extends Audit{

...

}


Hibernate Persistent Context and Session

The concept of Persistent Context and Session are central to the runtime behavior of Hibernate.

Persistent Context is a run time memory area where Hibernate holds the references of objects and

Session provides api to interact with the objects. Let's look them into one by one.


Persistent Context


At runtime whenever a session is opened and closed, between those open and close boundaries

Hibernate maintains the object in a Persistence Context. Think of it like a first level runtime cache

which hibernate controls. Hibernate does automatic dirty checking and transactional write-behind for

the entity managed in Persistent Context. Hibernate guarantee a scope of Java object identity in this

cache. Only one object instance representing a particular database row exists in the cache. Hibernate

can extend the persistence context to span a whole conversation.


Let's look at following piece of code. Here you can see the use of Session also.


//Persistent Context 1 Starts

Session session1 = HibernateUtil.getSessionFactory().openSession();

Student studentA = (Student)session1.get(Student.class, studentId);

Student studentB = (Student)session1.get(Student.class, studentId);

if(studentA == studentB){

System.out.println("Objects point to same refrence");

}
session1.close();

  //Persistent Context 1 Ends


  //Persistent Context 2 Starts

  Session session2 = HibernateUtil.getSessionFactory().openSession();

  Student studentC = (Student)session2.get(Student.class, studentId);

  if(studentA == studentC){

  System.out.println("Objects point to same refrence");

  }else{

  System.out.println("Objects do not point to same reference");

  }

  session2.close();

  //Persistent Context 2 Ends


  In the first case studentA and studentB will point to same object as Hibernate guarantees that against

  a same id only one object exist in the Persistent context. However in the second case studentA and

  studentC will be pointing to different objects as there is a different Persistent context. Hibernate does

  not maintains the guarantee beyond a Persistent Context Scope.


  Suppose after closing the session2, let's put all the objects in a set


  Set allStudents = new HashSet();

  allStudents.add(studentA);

  allStudents.add(studentB);

  allStudents.add(studentC);


  The set will only have two objects. The good practice is to avoid using detached object in situation like

  above outside of a persistent context or objects coming from different persistent context. Also make

  sure that the hashCode() and equals() method are properly overridden.


  Important points about Persistent Context:


Beware that hibernate keeps a snapshot of each persistent entity for dirty checking.

Keep the size of your persistent context to minimum. Keep an eye to your sql logs. Avoid object graphs.

Use session.evict(object) to clear big size objects once you are done with it. Use session.clear() when

you want to remove all objects.
Use session.setReadOnly(object,true) you can disable dirty checking for a particular instance.

  The biggest problem that comes with ORM solutions are performance problems and memory issues


  Session


  Hibernate provides api through Session object to handle database interaction task. The database

  interaction task are as follows:


Basic CRUD operation

Query Execution

Control of Transaction

Management of Persistent Context

  To make an object persistent, save is used


  Student tempStudent = new Student();

  tempStudent.setName("Om Shanti Om");



  session = HibernateUtil.getSessionFactory().openSession();

  Transaction tx = session.beginTransaction();

  session.save(tempStudent);

  tx.commit();

  session.close();


  To retrieve the object, we can use either load or get


  session = HibernateUtil.getSessionFactory().openSession();

  Transaction tx = session.beginTransaction();


  //Either use get or load to fetch the entity

  student = (Student)session.get(Student.class, studentId);

  //student = (Student)session.load(Student.class, studentId);


  tx.commit();

  session.close();
get() returns null if no database object for the id is found.load() throws ObjectNotFoundException.

Also load method may return a proxy and tries to avoid hitting the database.


session = HibernateUtil.getSessionFactory().openSession();

tx = session.beginTransaction();


Student loadStudent = (Student)session.load(Student.class, studentId);

//The database hit happens here

loadStudent.getName();


tx.commit();

session.close();


Hibernate automatically checks for the changes in the entity and flushes the changes to the database.


session = HibernateUtil.getSessionFactory().openSession();

Transaction tx = session.beginTransaction();


student = (Student)session.get(Student.class, studentId);

student.setName("Abhishek");

//No explicit call is made to update the record in database. Still the changes

//are flushed automatically


tx.commit();

session.close();


Data can be removed by calling delete on


Student loadStudent = (Student)session.load(Student.class, studentId);

session.delete(student);


An object has to be loaded in persistence context to use delete. The other option is to use bulk

operations which can issue direct deletes.Hibernate can also roll back the identifier of any entity that

has been deleted, it you enable the hibernate.use_identifier_rollback configuration option. The object

can than be treated as transient object.
After persistence context is closed, item becomes a detached instance. The detached object can be

handled using update or merge.If there is already an instance of object in the persistence context an

exception is thrown.


Managing Detached Entities


Detached entities can be managed again by calling update.


//update to student done outside of persistent scope

student.setName("abc");


session = HibernateUtil.getSessionFactory().openSession();

Transaction tx = session.beginTransaction();

//Reattaching. Hibernate will always issue an update,

//even if the object is not dirty


//The update can happens after attaching.

session.update(student);

student.setAddress(…);

tx.commit();

session.close();


The detached entity can be attached using lock


//Modification to a detached entity

session.setName("abc");


session = HibernateUtil.getSessionFactory().openSession();

Transaction tx = session.beginTransaction();


//Reattaching. Lockmodes are NONE, READ, UPDATE.

session.lock(student, LockMode.NONE);


//It matters where changes are called. If changes are called before locking only,

//the update is not issued

student.setAddress("Pune");
tx.commit();

session.close();


Merging


Merging merges the detached instance with the managed instance.


session.setName("oyejava");

session = HibernateUtil.getSessionFactory().openSession();

Transaction tx = session.beginTransaction();


session.merge(student);


tx.commit();

session.close();


Merging returns a new managed object. The detached instance remains detached. Merging includes all

value typed properties and all additions and removals of elements to any collection. Usually it‟s better

to discard the detached instance and continue the work with the managed entity.


Hibernate Entities Life cycle

The entities managed by Hibernate has a life cycle associated with them. Either you can make a new

object in heap and save it into database or the data can be fetched from the database and given to

user as database. The hibernate objects go through certain stages in the life cycle. Only entity objects

participate in the life cycle. The value objects do not participate in the life cycle. The stages in the life

cycle of an entity managed by Hibernate are as follows:


Transient Objects




When objects are created in the Java layer with new or similar operator and they have no

corresponding record existing in database than these objects are termed as Transient objects. These

objects exist in heap. The primary key attribute of this object is still not set. Transient objects are non

transactional and in fact Hibernate has no knowledge of these objects at this point of time, Objects

that are referenced only by other transient instances are, by default also transient. For an instance to
transition from transient to persistent state or to go managed state, it requires either a call to

  persistence manger or the creation of a reference from an already persistent instance.


  Persistent Objects




  Persistent entity is again an object in heap but it has a valid database identity associate with it.

  The entity goes into persistent object by one of following means:


Objects instantiated by application and then made persistent by calling one of the methods on the

persistent manager.

The objects become persistent when a reference is created from one of the persistent object.

The entities retrieved from the database either by doing query, lookup or navigating the object graph.

  Persistent instances are always associated with a persistent context and Hibernate knows about them

  and may track them for dirty checking.


  Removed Object




  An object scheduled for deletion either by calling delete or because of orphan deletion of entities. One

  should not use the object in Java layer as the database record will be deleted at the end of session. A

  logic build around these objects might get into trouble.


  Detached Object




  The object in persistent state go into detached state after the persistent context is closed.

  Detached objects can be brought into other persistent context by reattachment or merging. Detached

  object still has a valid primary key attribute but it is no longer managed by Hibernate.


  Concept of owning entity in EJB and Hibernate

  The owning entity concept confuses many of the early adopters of Hibernate and JPA aka Entity beans

  in EJB3.0. We often confuse with the notion that we have to tell which of the entity is the owner.
Before we delve deeper into this question let's understand why this whole notion of ownership comes

into picture. The persistence provider gives us a lot of goodies in terms of saving us from handling low

level sql handling and coding in terms of rows and columns. Even we get into this let's move one more

level above and understand that ORM framework provide us a way to think in terms of objects. The

thinking model with which Java programmers are comfortable with. OOAD is a very powerful notion as

it helps us in thinking in terms of real world. ATM, Customer, Item, Bid, Auction become reusable

notions in software world. However to provide that notion to Software world, ORM does a lot of dirty

work (dirty checking !!!) for us.


The most important feature that an ORM provides is transparent persistence. However to provide that

the ORM framework does a lot of work under the hood. For example Hibernate keeps a copy of original

entity from the database and before flushing does a dirty checking (Ahh I have heard this before). It

will compare the values with the working entity and in case of changes will generate the SQL.


Now let's take a concrete example of User and Address both having one to one and bidirectional

relationship. That means we have Address reference from User and User reference from Address. (It

does not matter whether we put the Fk on User side or Address side..Actually it matters with the kind

of Sql the ORM tool will generate to materialize the relationship). Let's say for this example the foreign

key is on User side.


Now as a good Java Programmer whenever we have to change the address of a user we will do

following:'


user.setAddress(add);

add.setUser(add);


If you are an EJB2.1 guy than please look into the EJB3.0. It's more work but with very simple

programming model and high portability.


Now ORM frameworks will do the dirty checking and it will figure out that User and Address both has

changed so it will issue a call to update both address and user.


For User it will be


update user set address_id =?
and for address it will be similar call. So for almost all bidirectional relationship ORM framework will

generate double update calls. This is a performance bottleneck Dr. Watson.


So what we do. We as a programmer tell that which side is the owning, which means for the

relationship to take into effect only one side of the dirty checking for the relationship needs to be

done. If we put inverse or mapped by on address than for the relationship to take effect we need to do


user.setAddress(add);


If we just do add.setUser(add) the change will not be propagated into the database. However as a

good programmer we should wire both side of the relationship.


Now let's think for a moment can ORM framework cannot handle this is some way.Think over it, it can

be done but will be a lot of bookkeeping and will complicate the frameworks a lot complex. Food for

thought!!!



Hibernate Query Language – HQL

Session api's are used when an entity needs to be fetched from the database. To fetch list of records

which might involve joins we have to use Hibernate Query Language (HQL). HQL queries are similar to

SQL. They are written in OO way. Hibernate supports criteria queries also which are type safe way of

writing queries. Hibernate supports the JPA QL also. Hibernate also supports issuing native SQL

queries. The Query interface is used to build and execute queries.


Fetching List


To fetch a list

In HQL:


Query hqlQuery = session.createQuery("Select s from Student s");

List<Student> listStudent = hqlQuery.list();


//Iterating the list

for(Student s: listStudent){

System.out.println(s.getName());

}
Using Criteria:


Criteria crit = session.createCriteria(PhoneEntity.class);

List<PhoneEntity> phones = crit.list();


for(PhoneEntity p: phones){

System.out.println(p.getNumber());

}


To restrict the list based on parameter

HQL way:


hqlQuery = session.createQuery ("from Student s where s.name like :name");


//The wild card can use used as similar to SQL

hqlQuery.setString("name", "ab%");


List<Student> listStudent = hqlQuery.list();


Using Criteria:


Criteria crit = session.createCriteria(Student.class);

crit.add(Restrictions.ilike(“name", “ab”);

List<Student> students = crit.list();


for(Student p: students ){

System.out.println(p.getName());

}


Pagination


Pagination is used when there are huge number of records and we want to fetch a subset of it. For

example we want to display the list of students on front end so we might just want to fetch the 25

records which we want to display in third page. So we want the record which starts at 51th row and

ends at 75th row


HQL way:
Query hqlQuery =

session.createQuery("from Student s order by s.name asc");


hqlQuery.setFirstResult(51);

hqlQuery.setMaxResults(25);


List<Student> listStudent = hqlQuery.list();


Criteria way:


Criteria crit = session.createCriteria(PhoneEntity.class);

crit.addOrder(Order.asc("number"));


crit.setFirstResult(51);

crit.setMaxResults(25);


List<PhoneEntity> phones = crit.list();


Binding Parameters


It's always a good practice to bind the parameters rather than building the queries by String

manipulation. It will protect from SQL injection also. For example do not do like

Select s from Student s where s.name like "James%".

Rather than use parameter binding. The parameters can be bound either using named parameter or

positional parameter. Names parameter is better as it is more maintainable and readable.


Named parameter binding:


hqlQuery = session.createQuery("from Student s where s.name like :name");


//The parameter is given a name

hqlQuery.setString("name", "James%");


List<Student> listStudent = hqlQuery.list();


Positional parameter binding:


hqlQuery = session.createQuery("from Student s where s.name like ?");
//The parameter is referred by position. For more than 1 parameter use number 0,1,2

//as thesequence used in query

hqlQuery.setString0, "James%");


listStudent = hqlQuery.list();


Scrolling with database cursor


Hibernate provides support for JDBC feature called scrollable result where the cursor is held on

database. To open the curosr


ScrollableResults itemCursor = session.createQuery(“from Student s).scroll();


The different functions to iterate using cursor


//Go to first record

itemCursor.first();


//Go to last record

itemCursor.last();


//Go to next record

itemCursor.next();


//Go to previous record

itemCursor.previous();


Named Query


Named query are queries where we give a name to it. These queries can bring performance as they

can be cached.


@NamedQuery{name=“findAllStudents”,

query=“SELECT s from Student s where s.firstName LIKE :firstName”)


Calling the query:


Query query = em.createNamedQuery(“findAllStudents”);
Polymorphic Queries


Hibernate supports polymorphic query. For example suppose we have an inheritance structure on the

OO side as mentioned in ((Hibernate Mapping Inheritance)).It does not matter whichever strategy you

use, Hibernate will ensure to fetch the record as per polymorphism.


If the query is "Select u from User u", hibernate will fetch all the records form User, Customer and

Employee table.


Expressions


Hibernate supports the expression which can narrow down results as per some criteria.

Some example of expression are


//amount between 1 and 10

from Student s where s.pendingAmount between 1 and 10


//amount > 100

from Student s where s.pendingAmount > 100


//Only those students whose email is as mentioned

from Student s where s.email in („a@a.com‟,‟b@b.com‟)


//students whose email are not set

where s.email is null


//students whose mails are set

where s.email is not null


//student refers to a phone collection and the collection is not empty

from Student i where i.phones is not empty


Hibernate supports function also


//lowering the name and than comparing

from Student s where lower(s.name) like…
//Concatenating the name and than comparing as the database is having only one name field

//which contains both first and last name together

from Student s where concat(s.firstName,s.lastName) like..


//Student has a collection of phone and has more than 2 phones.

From Student s where size(s.phones) > 2


//current_date will calculate the date and return

Select upper(s.name), current_date() from Student s


Fetching Multiple Objects


Multiple objects can be fetched as an object array.


//It will return an Object [ ] with Student at index 0 and User at index 1

Select s , u from Student s, User u


Scalar queries or Projection


This is very useful in reporting. Fetching a lot of objects when we are looking for only some column

data or want data from different tables leads to performance bottlenecks. In these cases it's better to

use scalar queries as it fetched only required data


Select s.name , s.pendingAmount from Student s


This query will return an Object[].It‟s a scalar queries and the data fetched is not associated with

persistence context. The fetched data is not managed for dirty states.


Query Hints


The flush mode can be disabled while executing the query. This can be useful when you do not want

Hibernate to issue a flush before executing the query. For example if before executing the query you

know that the results of the query is not going to be affected by the dirty states of entities in the

session, for performance reason it's better to disable the flush.


//Query way

Query q = session.createQuery(queryString).setFlushMode(FlushMode.COMMIT);
//Criteria way

Criteria c = session.createCriteria(Student.class).setFlushMode(FlushMode.COMMIT);


//JPA way

Query q = em.createQuery(queryString).setFlushMode(FlushModeType.COMMIT);


The cache mode can also be disabled while executing query.It tells hibernate to not to put any entities

in the second level cache


//Query way

Query q = session.createQuery(queryString).setCacheMode(CacheMode.COMMIT);


//Critera way

Criteria c = session.createCriteria(Student.class).setCacheMode(CacheMode.COMMIT);


//In JPA this is not supported as standard.

If hibernate is the JPA provider than it can be used

//using hibernate feature.

Query q = em.createQuery(queryString).setHint

(“org.hibernate.cacheMode”,org.hibernate.CacheMode.IGNORE);


Dirty checking on the fetched objects can also be disabled. When you know that the fetched objects

are not going to change it's better to disable the dirty checking. For example in case of fetching the

list of objects for display purpose only


//Query way

Query q = session.createQuery(queryString).setReadOnly(true);


//Criteria way

Criteria c = session.createCriteria(Student.class).setReadOnly(true);


//In JPA this is not supported as standard.

//If hibernate is the JPA provider than it can be used using hibernate feature.

Query q = em.createQuery(queryString).setHint(“org.hibernate.readOnly”, true);


A timeout can also be passed as query hint which tells how long a long running query can be allowed
//Query way

Query q = session.createQuery(queryString).setTimeout(60);


//Criteria way

Criteria c = session.createCriteria(Student.class).setTimeout(60);


//In JPA this is not supported as standard.

//If hibernate is the JPA provider than it can be used using hibernate feature.

Query q = em.createQuery(queryString).setHint(“org.hibernate.timeout”,60);



Hibernate Shards

Sharding is basically horizontal partitioning of data. If handled carefully, sharding can improve

performance. For example let's say for a online mail provider, the mail subscribers can run into huge

numbers. If all the rows of the database are sitting in the same server, it would hog a huge amount of

memory. Sharding can help in horizontal partitioning of data. We can partition the records on the

basic of continents. The continent information derived from the country information. So the rows

belonging to North America and Asia would be sitting on different servers. If the queries are always

continent specific most of the time, this partitioning will help in improving the performance and also

indexing will be better. The care should be taken that if we have queries which involve going to

different databases to fetch the result set, and if this is a prevalent scenario, sharding would result in

degradation of performance.


Hibernate Shards helps in dealing with horizontal partitioning of data. To use shards, let's assume we

have a EmailUser table where the user data is saved. We will save the records alternately in two

different database and will see that how hibernate shields us from the knowledge that it is talking to

two different database. To make this tutorial, make a java project as outlined in Hibernate

Introduction with Annotation. Also make sure Hypersonic jar is in the path. We will make a tutorial

where the data is saved to two databases. The source code can be downloaded from the attachment

section down below.


Let's make the EmailUser class first. Note that it is a simple mapping class.


@Entity
public class EmailUser {
private BigInteger id;
          private String name;
          private String continent;


           //The id is generated by using a Shard specific generator
          @Id
           @GeneratedValue(generator="EmailIdGenerator")
          @GenericGenerator(name="EmailIdGenerator",
                   strategy="org.hibernate.shards.id.ShardedUUIDGenerator")
          @Column(name="ID")
          public BigInteger getId() {
                     return id;
          }


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


          //Getters and setters for other properties
           ...
}

As we are interacting with two different databases, we need to provide two configuration file to

Hibernate. If there are more than two databases, we have to provide same number of configuration

files. Each file representing the details of a database. The first configuration file is usually the master

file, where we provide all the details about other settings. Rest of the configuration files just contains

the details of connection to database and shard specific id's.


hibernate0.cfg.xml (First configuration file)


<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
           "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-
3.0.dtd">


<hibernate-configuration>
    <!-- note the different name -->
    <session-factory name="HibernateSessionFactory0">


    <!-- Database connection settings -->
    <property
name="connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property
name="connection.url">jdbc:hsqldb:hsql://localhost</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"></property>


    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>


    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.HSQLDialect</property>


    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>


    <!-- Second-level cache    -->
    <property
name="cache.provider_class">org.hibernate.cache.EhCacheProvider/>


    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>
    <!--    property name="format_sql">true</property -->
    <!-- property name="use_sql_comments">true</property -->
<!-- Drop and re-create the database schema on startup -->
     <property name="hbm2ddl.auto">create-drop</property>


     <!-- Shard specific confifuration -->
     <property name="hibernate.connection.shard_id">0</property>
     <property
name="hibernate.shard.enable_cross_shard_relationship_checks">
     true
     </property>


          </session-factory>
</hibernate-configuration>




The hibernate configuration for second database

hibernate1.cfg (Second Configuration file)


<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-configuration-
3.0.dtd">


<hibernate-configuration>
    <!-- note the different name -->
    <session-factory name="HibernateSessionFactory0">


    <!-- Database connection settings, this database is in memory -->
    <property
name="connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property name="connection.url">jdbc:hsqldb:file:1</property>
<property name="connection.username">sa</property>
    <property name="connection.password"></property>


    <!-- SQL dialect - This tells the SQL grammer to be used -->
    <property name="dialect">org.hibernate.dialect.HSQLDialect</property>


    <property name="hibernate.connection.shard_id">1</property>
    <property
        name="hibernate.shard.enable_cross_shard_relationship_checks">
       true
    </property>
</session-factory>
</hibernate-configuration>

In the true tradition of Hibernate, now we write the HibernateUtil class which is responsible for

building sessionFactory


public class HibernateUtil {


    private static SessionFactory sessionFactory;


    static{
       try{
          //Provide the master hibernate config
          AnnotationConfiguration prototypeConfig =
                  new
AnnotationConfiguration().configure("hibernate0.cfg.xml");
          prototypeConfig.addAnnotatedClass(EmailUser.class);
          List<ShardConfiguration> shardConfigs =
                  new ArrayList<ShardConfiguration>();
          shardConfigs.add(buildShardConfig("hibernate0.cfg.xml"));
          shardConfigs.add(buildShardConfig("hibernate1.cfg.xml"));
ShardStrategyFactory shardStrategyFactory =
buildShardStrategyFactory();
         ShardedConfiguration shardedConfig =
            new ShardedConfiguration(prototypeConfig,
                                   shardConfigs,
                                   shardStrategyFactory);


         sessionFactory =   shardedConfig.buildShardedSessionFactory();
        }catch(Throwable ex){
               throw new ExceptionInInitializerError(ex);
        }
}


    static ShardConfiguration buildShardConfig(String configFile) {
        Configuration config = new Configuration().configure(configFile);
        return new ConfigurationToShardConfigurationAdapter(config);
    }


    static ShardStrategyFactory buildShardStrategyFactory() {
        ShardStrategyFactory shardStrategyFactory =
               new ShardStrategyFactory() {
               public ShardStrategy newShardStrategy(List<ShardId>
shardIds) {
               RoundRobinShardLoadBalancer loadBalancer =
                      new RoundRobinShardLoadBalancer(shardIds);
               ShardSelectionStrategy shardSelection=
                      new RoundRobinShardSelectionStrategy(loadBalancer);
               ShardResolutionStrategy shardResoultion =
                      new AllShardsShardResolutionStrategy(shardIds);
               ShardAccessStrategy shardAccess =
                      new SequentialShardAccessStrategy();
               return new ShardStrategyImpl(shardSelection,
Object relationship mapping and hibernate
Object relationship mapping and hibernate
Object relationship mapping and hibernate
Object relationship mapping and hibernate
Object relationship mapping and hibernate
Object relationship mapping and hibernate
Object relationship mapping and hibernate

Más contenido relacionado

La actualidad más candente

Module 5 oodb systems semantic db systems
Module 5 oodb systems  semantic db systemsModule 5 oodb systems  semantic db systems
Module 5 oodb systems semantic db systems
Taher Barodawala
 
Object oriented database model
Object oriented database modelObject oriented database model
Object oriented database model
PAQUIAAIZEL
 
Unit1 rdbms study_materials
Unit1 rdbms study_materialsUnit1 rdbms study_materials
Unit1 rdbms study_materials
gayaramesh
 
9. Object Relational Databases in DBMS
9. Object Relational Databases in DBMS9. Object Relational Databases in DBMS
9. Object Relational Databases in DBMS
koolkampus
 
Unit 4 rdbms study_material
Unit 4  rdbms study_materialUnit 4  rdbms study_material
Unit 4 rdbms study_material
gayaramesh
 

La actualidad más candente (20)

Dbms viva questions
Dbms viva questionsDbms viva questions
Dbms viva questions
 
Bca examination 2015 dbms
Bca examination 2015 dbmsBca examination 2015 dbms
Bca examination 2015 dbms
 
Odbms concepts
Odbms conceptsOdbms concepts
Odbms concepts
 
Types of keys in database management system by Dr. Kamal Gulati
Types of keys in database management system by Dr. Kamal GulatiTypes of keys in database management system by Dr. Kamal Gulati
Types of keys in database management system by Dr. Kamal Gulati
 
Module 5 oodb systems semantic db systems
Module 5 oodb systems  semantic db systemsModule 5 oodb systems  semantic db systems
Module 5 oodb systems semantic db systems
 
Object oriented database model
Object oriented database modelObject oriented database model
Object oriented database model
 
Unit 3 rdbms study_materials-converted
Unit 3  rdbms study_materials-convertedUnit 3  rdbms study_materials-converted
Unit 3 rdbms study_materials-converted
 
DBMS CS 4-5
DBMS CS 4-5DBMS CS 4-5
DBMS CS 4-5
 
Entity-Relationship Data Model in DBMS
Entity-Relationship Data Model in DBMSEntity-Relationship Data Model in DBMS
Entity-Relationship Data Model in DBMS
 
Dbms models
Dbms modelsDbms models
Dbms models
 
Data modelingpresentation
Data modelingpresentationData modelingpresentation
Data modelingpresentation
 
Unit1 rdbms study_materials
Unit1 rdbms study_materialsUnit1 rdbms study_materials
Unit1 rdbms study_materials
 
Introductin to Data Modeling.
Introductin to Data Modeling.Introductin to Data Modeling.
Introductin to Data Modeling.
 
Object oriented database
Object oriented databaseObject oriented database
Object oriented database
 
Ch8
Ch8Ch8
Ch8
 
9. Object Relational Databases in DBMS
9. Object Relational Databases in DBMS9. Object Relational Databases in DBMS
9. Object Relational Databases in DBMS
 
Object Oriented Database Management System
Object Oriented Database Management SystemObject Oriented Database Management System
Object Oriented Database Management System
 
Unit 2 rdbms study_material
Unit 2  rdbms study_materialUnit 2  rdbms study_material
Unit 2 rdbms study_material
 
Ordbms
OrdbmsOrdbms
Ordbms
 
Unit 4 rdbms study_material
Unit 4  rdbms study_materialUnit 4  rdbms study_material
Unit 4 rdbms study_material
 

Destacado

Classloading and Type Visibility in OSGi
Classloading and Type Visibility in OSGiClassloading and Type Visibility in OSGi
Classloading and Type Visibility in OSGi
martinlippert
 
Hibernate Presentation
Hibernate  PresentationHibernate  Presentation
Hibernate Presentation
guest11106b
 

Destacado (10)

Proxy & CGLIB
Proxy & CGLIBProxy & CGLIB
Proxy & CGLIB
 
Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001
 
Dynamic Proxy by Java
Dynamic Proxy by JavaDynamic Proxy by Java
Dynamic Proxy by Java
 
Classloading and Type Visibility in OSGi
Classloading and Type Visibility in OSGiClassloading and Type Visibility in OSGi
Classloading and Type Visibility in OSGi
 
hibernate with JPA
hibernate with JPAhibernate with JPA
hibernate with JPA
 
Understanding Java Dynamic Proxies
Understanding Java Dynamic ProxiesUnderstanding Java Dynamic Proxies
Understanding Java Dynamic Proxies
 
AWS CloudFormation en 5 Minutos
AWS CloudFormation en 5 MinutosAWS CloudFormation en 5 Minutos
AWS CloudFormation en 5 Minutos
 
Hibernate in Action
Hibernate in ActionHibernate in Action
Hibernate in Action
 
Hibernate Presentation
Hibernate  PresentationHibernate  Presentation
Hibernate Presentation
 
Modern SQL in Open Source and Commercial Databases
Modern SQL in Open Source and Commercial DatabasesModern SQL in Open Source and Commercial Databases
Modern SQL in Open Source and Commercial Databases
 

Similar a Object relationship mapping and hibernate

01 Persistence And Orm
01 Persistence And Orm01 Persistence And Orm
01 Persistence And Orm
Ranjan Kumar
 
data base system to new data science lerne
data base system to new data science lernedata base system to new data science lerne
data base system to new data science lerne
tarunprajapati0t
 
Student POST  Database processing models showcase the logical s.docx
Student POST  Database processing models showcase the logical s.docxStudent POST  Database processing models showcase the logical s.docx
Student POST  Database processing models showcase the logical s.docx
orlandov3
 
Database System Concepts AND architecture [Autosaved].pptx
Database System Concepts AND architecture [Autosaved].pptxDatabase System Concepts AND architecture [Autosaved].pptx
Database System Concepts AND architecture [Autosaved].pptx
Koteswari Kasireddy
 
Document Based Data Modeling Technique
Document Based Data Modeling TechniqueDocument Based Data Modeling Technique
Document Based Data Modeling Technique
Carmen Sanborn
 
Unit1 jaava
Unit1 jaavaUnit1 jaava
Unit1 jaava
mrecedu
 

Similar a Object relationship mapping and hibernate (20)

Mc0077 – advanced database systems
Mc0077 – advanced database systemsMc0077 – advanced database systems
Mc0077 – advanced database systems
 
01 Persistence And Orm
01 Persistence And Orm01 Persistence And Orm
01 Persistence And Orm
 
M.c.a. (sem iv)- java programming
M.c.a. (sem   iv)- java programmingM.c.a. (sem   iv)- java programming
M.c.a. (sem iv)- java programming
 
Class notes(week 2) on basic concepts of oop-2
Class notes(week 2) on basic concepts of oop-2Class notes(week 2) on basic concepts of oop-2
Class notes(week 2) on basic concepts of oop-2
 
Data Oriented Programming in Java.pdf
Data Oriented Programming in Java.pdfData Oriented Programming in Java.pdf
Data Oriented Programming in Java.pdf
 
Class notes(week 2) on basic concepts of oop-2
Class notes(week 2) on basic concepts of oop-2Class notes(week 2) on basic concepts of oop-2
Class notes(week 2) on basic concepts of oop-2
 
data base system to new data science lerne
data base system to new data science lernedata base system to new data science lerne
data base system to new data science lerne
 
Data Oriented Programming in Java
Data Oriented Programming in JavaData Oriented Programming in Java
Data Oriented Programming in Java
 
Student POST  Database processing models showcase the logical s.docx
Student POST  Database processing models showcase the logical s.docxStudent POST  Database processing models showcase the logical s.docx
Student POST  Database processing models showcase the logical s.docx
 
MCA NOTES.pdf
MCA NOTES.pdfMCA NOTES.pdf
MCA NOTES.pdf
 
Interview questions(programming)
Interview questions(programming)Interview questions(programming)
Interview questions(programming)
 
Core Java Interview Questions with Answers.pdf
Core Java Interview Questions with Answers.pdfCore Java Interview Questions with Answers.pdf
Core Java Interview Questions with Answers.pdf
 
Free Hibernate Tutorial | VirtualNuggets
Free Hibernate Tutorial  | VirtualNuggetsFree Hibernate Tutorial  | VirtualNuggets
Free Hibernate Tutorial | VirtualNuggets
 
Advance Database Management Systems -Object Oriented Principles In Database
Advance Database Management Systems -Object Oriented Principles In DatabaseAdvance Database Management Systems -Object Oriented Principles In Database
Advance Database Management Systems -Object Oriented Principles In Database
 
Database System Concepts AND architecture [Autosaved].pptx
Database System Concepts AND architecture [Autosaved].pptxDatabase System Concepts AND architecture [Autosaved].pptx
Database System Concepts AND architecture [Autosaved].pptx
 
Introduction to odbms
Introduction to odbmsIntroduction to odbms
Introduction to odbms
 
Document Based Data Modeling Technique
Document Based Data Modeling TechniqueDocument Based Data Modeling Technique
Document Based Data Modeling Technique
 
Asp.net interview questions
Asp.net interview questionsAsp.net interview questions
Asp.net interview questions
 
Unit1 jaava
Unit1 jaavaUnit1 jaava
Unit1 jaava
 
Cse ii ii sem
Cse ii ii semCse ii ii sem
Cse ii ii sem
 

Último

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Último (20)

Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 

Object relationship mapping and hibernate

  • 1. Object Relationship Mapping (ORM) ORM stands for Object relational Mapping. ORM is an attempt to map the notion of object and relational world so that they can talk to each other in a easy way. Any non trivial application has a database behind it and Java applications are no exception. In fact if we look closely into any application, one will realize that the application gets more or less modeled around the data model. In database technology, relational database are the clear winners. Other database technologies has come and gone. Relational concept of data management was first introduced by E.F. Codd in 1970. An analogy for relational model can be drawn with spreadsheets. Each sheet represents a table and the columns in the sheet represent the table attributes. Each instance of data is represented by the rows. The data in different sheets are connected with each other by referring to the data point using the sheet number, column number and row number. This is what is called as foreign key relationship in database technology. In fact most of the GUI interfaces to database show the data in a spreadsheet format. To interact with the database, Standard Query Language(SQL) has emerged as the standard way. The SQL standards are controlled by ANSI. However there are still proprietary variations to it. SQL provides two types of mechanism: Data Definition Language (DDL) : Provides ways to create and alter tables. Data Manipulation Language (DML) : Provides ways to manipulate and retrieve data. It includes inserting, updating and deleting data. To interact with the database, the applications has to issue SQL to the database. How to issue SQL is proprietary to each database. They have their own API's exposed for this and the API's might be written in different languages. For example a database written in C language. might expose C based API's. Considering that the data independence is considered a virtue for any application, it would be a lot of work for an application developer to understand the interfaces for each of the database and implement it. To solve this kind of porblem, Java has come up with ((JDBC)) API's. JDBC is the most popular way of connecting to databases in Java. It's an interface based API where the implementation for each database is provided by the drivers for particular database. Though JDBC is very popular, it is inherently relational in nature. The basic problem is the mismatch in conceptual level between relational technology and Object Oriented Technology. Java being a pure Object
  • 2. Oriented Language, this mismatch is important to deal with. This mismatch is also known as Object relational mismatch. ORM tries to solve this mismatch. Let's see the kind of mismatch that are there: Inheritance Java supports inheritance. For example we might have User class from which Student and Teacher class is derived. User public class User{ private String Name; //Setters and getters } Student public class Student extends User{ private double percentage; //Setter and Getter } Teacher public class Teacher extends User{ private int exprienceYears; //Setters and Getters } Now think for a moment how you are going to map these classes to the table structure. ORM frameworks adopt different strategies to solve this, which can be seen at ((Hibernate)) section.
  • 3. Also with this comes the mismatch in terms of polymorphism. A reference of User type can refer to an object of Student or Teacher. Also a list might contain a mix of Teacher, Student and User objects. How you build those list by querying database. The ORM frameworks has to somehow differentiate that the data is belonging to User or Student or Teacher. Granularity The granularity problem comes when the number of classes mapping to number of tables in the database do not match. For example let's say we have the User class which has an Address object public class User{ private String Name; private Address address; //Setters and getters } Address public class Address{ private String city; private String country; //Setters and getters Also the table structure for User is Table USER: NAME CITY COUNTRY There is one table but the data is sitting in two objects. The same problem can come the other way round also where you have two tables and one class containing all the data points. ORM frameworks has to care of this mismatch in terms of different number of tables mapped to different number of classes.
  • 4. Identity and Equality The notion of identity is driven by primary key in relational model. Given a primary key you will always retrieve the same data. Also it does not matter, how many clients are retrieving the same data. With right isolation level all will see the same data. In Java the situation becomes more complex. The same data row might be represented by more objects in Java layer. For example a User data in database with primary key 1 might have more than one object in different thread. The question comes which is the object having the right data. Also if all thread try to save the same object, than who wins? Similar problem arises related to equality. In Java the default is reference equality. If the references are pointing to the same object than they are equal. The corollary is that if there are two objects representing the same data row, they will come out as different. To solve this we have to give implementation to the equals methos, but it's not always trivial. ORM solutions has to provide provisions to maintain the correct notion of equality and identity. The frameworks usually ask to explicitly map the primary key to an attribute. Association In Java the relationship is done by association. For example User has a reference of address. However in Tables, the relationship is done with foreign key association. Java has also the notion of directionality. For example you can access address form User but not the other way round. To build the relationship from both side you have to put the reference on both the sides. User public class User{ private Address address; //Setters and Getters } Address public class Address{ private User user; //setters and getters }
  • 5. However there is no notion of directionality in the relational world.The foreign key relationship can be done at any one end and the relationship is build. With SQL you can navigate from any end. For example the foreign key relationship build at User side will be Table ADDRESS ADDRESS_ID CITY COUNTRY Table USER USER_ID NAME ADDRESS_ID (Fk) ORM solutions has to deal with these association while setting and getting the data from the database. Type Systems Object Oriented and relational world has different type systems. For example in relational world string can be constrained on the size however on the Java side you can point the reference of String to any size based on memory allocated. Also date and times are handled differently in Java and relational world. For example in some databases there is a distinction between date, time and timestamp. Time stamp contains both date and time. In Java, the date is a long value which contains the date and time both. So when you fetch the date or time from relational world how you map it to a Java data type of Date or Calendar. Databases are Different There are so many popular databases in the market. In spite of SQL being a standard, there are still variations in the SQL support in each database and there are many vendor extensions and individual flavors in each database. Though this is not really an ORM issue but it is important from the perspective of database portability, if you are looking for it. Ensuing database portability using JDBC is usually a hurricane task if you wish to use the individual flavors of database for performance or other reasons. ORM frameworks attempt to handle most of the important databases transparently. Also they do have extension mechanisms if you wish to support another database
  • 6. A video explaining the above concepts: ORM frameworks adopt different strategies to solve these kind of mismatches. ORM frameworks strive to preserve the notion of object world concepts and shield the developers from relational world by taking care of mappings. This should be taken as an excuse to not to learn relational concepts. In fact on the other way to be a good user of ORM frameworks, one should understand how the mapping works and the implications of it. The number issue in using ORM frameworks is performance and most of the time its because of not understanding how the ORM frameworks map to the relational world and not having a good grasp of relational world concepts. Hibernate Introduction Hibernate is an ORM framework. It provides capability to interact with database in an object oriented way. Hibernate provides its own HQL (Hibernate query language) also. The concepts of ORM are now adopted in EJB3.0 in the form of entity beans and Jave Persistence API (JPA). Hibernate supports Entity beans also. This means hibernate can act as an implementation provider for Entity beans. In fact, JBoss uses hibernate as implementation provider for Entity beans. Hibernate has its own set of API's also which at the moment are richer than JPA. Going forward however we might see Entity beans and JPA closing this gap. Let's make a Java project where we will persist the data into the database. First download the Hibernate Core from https://www.hibernate.org/6.html. Unzip the download at a location and you will find the following important directories/file in it (This might be different from what you see as hibernate keeps on changing the structure). doc - contains the reference document for hibernate eg - example application etc - configuration files grammer lib - contains dependencies for hibernate. See lib/_README.txt for details about libraries. src - source code of hibernate test - test suite
  • 7. hibernate3.jar - hibernate library Make a simple Java application in your IDE. Have the following libraries in the build path: From Hibernate Core (<hibernate-distribution-*>/lib/required) antlr-2.7.6 commons-collections-3.1.jar dom4j-1.6.1.jar javassist-3.9.0.GA.jar jta-1.1.jar slf4j-api-1.5.8.jar <hibernate-distribution-*>/lib/ -Choose between cglib or javassist <hibernate-distribution>/*hibernate3.jar Download slf4j from http://www.slf4j.org/dist/ slf4j-simple-1.5.8.jar hsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar. Hibernate is a Object relational mapping framework. What it will help us is in saving the objects into the relational world. So let's have our Java class whose object instances at runtime will be saved by hibernate to the database. public class Student { //Id will correspond the primary key in the database private Long id; protected String name; public Long getId() { return id; } public void setId(Long id) {this.id = id;} public String getName() {return name;} public void setName(String name) {this.name = name;} }
  • 8. Now we have the domain class definition with us. Now we will put a mapping file which will map this class to the data model in the database. We are not creating the table in the database as we will use hibernate to generate the data model. Though in real life application you would have your data model already created and placed in the database. Student.hbm.xml (Put it together with Student class) <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- class attributes - name - Java class name table - Table to which this class is mapped schema - The schema where it sits id - name - name of property on Java class. It will result in getId() and setId method column - column in table to which it is mapped generator- how the id's to be generated --> <class name="com.oyejava.Student" table="Student" schema="PUBLIC"> <id name="id" column="STUDENT_ID"> <generator class="increment"/> </id> <!-- name - name of property in Java class. getName() and setName() column - column in table to which it is mapped. --> <property name="name" column="NAME" /> </class> </hibernate-mapping> Now we will provide hibernate the details to connect to the database. Similar to JDBC coding, the connection details and drivers need to be provided to Hibernate. We will use hsql, the details of which
  • 9. can be seen at HypersonicThis is done in a XML file. hibernate.cfg.xml (Put it in the class path) <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings --> <!-- If the below drive does not works try org.hsqldb.jdbc.JDBCDriver--> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:hsql://localhost</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect - This tells the SQL grammer to be used --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <!-- Log out all the sql that hibernate is issuing to datbase. This is very useful for debugging --> <property name="show_sql">true</property> <!-- Create the table looking at class and mapping. Very useful in development Use validate in production environments. --> <property name="hbm2ddl.auto">create</property>
  • 10. <!-- Mapping file. --> <mapping resource="com/oyejava/Student.hbm.xml"/> </session-factory> </hibernate-configuration> Now we will write a utility class which will start the session factory of hibernate, if it is not started and will return the Session factory. This is the most used pattern of boot strapping Hibernate. Session factory contains all the configuration information at runtime. A Session is retrieve from the Session factory. A session is a light weight object which provide services to interact with database. You can think of Session like JDBC connection, thought it may not open the database connection if not required. HibernateUtil public class HibernateUtil { private static SessionFactory sessionFactory; static{ try{ //By default it will look for hibernate.cfg.xml in the class path sessionFactory=new Configuration().configure().buildSessionFactory(); }catch(Throwable ex){ throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory(){ return sessionFactory; } public static void shutdown(){ //Close caches and connection pool getSessionFactory().close(); }
  • 11. } Now let's write the main class in which we will create a Student object and persist it to database public class HibernateBasic { public static void main(String[] args) { //Get the session from the Session factory Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx= session.beginTransaction(); Student student = new Student(); student.setName("oyeJava"); Long studentId = (Long)session.save(student); System.out.println(studentId); tx.commit(); session.close(); } } Run the application and check in the database. It should persist a row of data. Download the source code from down below in the attachment section. The libraries has to be included as per the list given above. In the above example we saw how to configure hibernate using XML mapping. The present trend is however to move towards annotation based mapping.
  • 12. Hibernate Introduction with Annotation Before Java 5, Hibernate has XML way of configuring things. However with introduction of Annotations, the world has changed a lot. Many frameworks has adopted annotations as an alternative to XML. Hibernate has also adopted annotation. The XML way is still supported but annotation is the predominant way of working now. We will do the same example as we did in Hibernate Introduction using annotation. Download the Hibernate Core and Hibernate Annotations from https://www.hibernate.org/6.html. Let's make a Java project and pull the following libraries. From Hibernate Core (<hibernate-distribution-*>/lib/required) antlr-2.7.6 common-collections-3.1.jar dom4j-1.6.1.jar hibernate3.jar javassist-3.9.0.GA.jar jta-1.1.jar slf4j-api-1.5.8.jar <hibernate-distribution-*>/lib/ -Choose between cglib or javassist From Hibernate Annotation: lib/ejb3-persistence.jar lib/hibernate-commons-annotations.jar hibernate-annotations.jar Download slf4j from http://www.slf4j.org/ slf4j-simple-1.5.8.jar Hypersonic: hsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar. For details see ((Hypersonic)).
  • 13. Now let's write our domain class which is Student class. Student //Entity annotation represents that it is an entity class and is //mapped to a table in database. Table annotation tells about the //table name to which this entity is mapped @Entity @Table(name="Student") public class Student { //Id will correspond the primary key in the database private Long id; protected String name; //Id - Represents that it is a primary key column //GeneratedValue - How the key to be generated //column - Column to which this property is mapped @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="STUDENT_ID") public Long getId() { return id; } public void setId(Long id) { this.id = id; } //There is annotation here so by default it is mapped to //the column with name NAME. In annotation, the properties are //by default mapped. In XML mapping by default the columns //are not mapped. public String getName() { return name; }
  • 14. public void setName(String name) { this.name = name; } } If you have done the Hibernate Introduction, you will realize that the mapping has been pulled in the class file itself in terms of annotations. The parallel can easily be drawn. Also now we do not need any mapping hbm.xml file. We still need the configuration XML, though the mapping will be done by referencing to class hibernate.cfg.xml (Put it in the class path) <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings --> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:hsql://localhost</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect - This tells the SQL grammer to be used --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
  • 15. <!-- Log out all the sql that hibernate is issuing to datbase. This is very useful for debugging --> <property name="show_sql">true</property> <!-- validates the table structure as per mapping definition. --> <property name="hbm2ddl.auto">validate</property> <!-- Mapping class. --> <mapping class="com.oyejava.Student"/> </session-factory> </hibernate-configuration> Let's write the Hibernate util class which is a utility class to make the Hibernate session factory. The Session factory at runtime contains all the configuration and mapping details. From Session factory we can get the Session, which is a lightweight object and helps us in interacting with the database. Session can be thought of as a Connection as in JDBC thought the Session may choose to not to open the connection to the database. HibernateUtil public class HibernateUtil { private static SessionFactory sessionFactory; static{ try{ //By default it will look for hibernate.cfg.xml in the class path sessionFactory=new AnnotationConfiguration().configure().buildSessionFactory(); }catch(Throwable ex){ throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory(){ return sessionFactory; }
  • 16. public static void shutdown(){ //Close caches and connection pool getSessionFactory().close(); } } Now in the application logic, in this case in the main method we can create a Student object and save it to the database. public class HibernateBasic { public static void main(String[] args) { //Get the session from the Session factory Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx= session.beginTransaction(); Student student = new Student(); student.setName("oyeJava"); Long studentId = (Long)session.save(student); System.out.println(studentId); tx.commit(); session.close(); } } Those who have done the hibernate in the XML way will notice that the only difference the two has got is in terms of where the mapping is kept. You can download the source code from the attachment section down below.
  • 17. Hibernate For Entity Beans of EJB Hibernate also support Entity beans and Java Persistence Provider(JPA) of EJB3.0+ specification. In fact many of the concepts of Entity beans has been taken from Hibernate. JBoss application server uses Hibernate as the default persistence provider for Entity beans and JPA. JPA has the notion of persistence unit which represents the configuration. EntityManagerFactory of JPA corresponds to SessionFactory and EntityManager corresponds to Session. Let's do the ((Hibernate Introduction with Annotation)) example of persisting Student object using Entity beans and JPA API's Download the Hibernate Core, Hibernate Annotations and Hibernate EntityManager from https://www.hibernate.org/6.html . Let's make a Java project and pull the following libraries. From Hibernate Core (<hibernate-distribution-*>/lib/required) antlr-2.7.6 commons-collections-3.1.jar dom4j-1.6.1.jar hibernate3.jar javassist-3.9.0.GA.jar jta-1.1.jar slf4j-api-1.5.8.jar <hibernate-distribution-*>/lib/ -Choose between cglib or javassist From Hibernate Annotation: lib/ejb3-persistence.jar lib/hibernate-commons-annotations.jar hibernate-annotations.jar From Hibernate Entity Manager: lib/jboss-archive-browsing.jar hibernate-entitymanager.jar
  • 18. Download slf4j from http://www.slf4j.org/ slf4j-simple-1.5.8.jar Hypersonic: hsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar. For details see ((Hypersonic)). Now let's write our domain class which is Student class.Note that it the same class as we did in ((Hibernate Introduction with Annotation)) Student //Entity annotation represents that it is an entity class and is //mapped to a table in database. Table annotation tells about the //table name to which this entity is mapped @Entity @Table(name="Student") public class Student { //Id will correspond the primary key in the database private Long id; protected String name; //Id - Represents that it is a primary key column //GeneratedValue - How the key to be generated //column - Column to which this property is mapped @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="STUDENT_ID") public Long getId() { return id; } public void setId(Long id) { this.id = id; }
  • 19. //There is annotation here so by default it is mapped to //the column with name NAME. In annotation, the properties are //by default mapped. In XML mapping by default the columns //are not mapped. public String getName() { return name; } public void setName(String name) { this.name = name; } } Now let's write persistence.xml. This is the configuration file that EJB mandates. It is similar to what hibernate configuration file does. It can support multiple persistence provider other than hibernate also. persistence.xml (Put in META-INF folder under source folder) <?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"> <!-- This name is used to refer to this persistence context. This will be used while we make the EntityManagerFactory --> <persistence-unit name="hibernateMapping"> <!-- Persistence provider --> <provider>org.hibernate.ejb.HibernatePersistence</provider> <!-- Provide properites of persistence provider. This is specific to each persistence provider. All hibernate related properties which sit in hibernate.cfg.xml can be put here. --> <properties> <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/> <property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost"/>
  • 20. <property name="hibernate.connection.username" value="sa"/> <property name="hibernate.connection.password" value=""/> </properties> </persistence-unit> </persistence> Now we just have to write our main class and start interacting with database. public class HibernateMappingJPA { public static void main(String[] args) { //The name hibernateMapping comes from persistence.xml EntityManagerFactory emf = Persistence.createEntityManagerFactory("hibernateMapping"); //EntityManager is similar to Session in hibernate EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Student student = new Student(); student.setName("James Bond"); em.persist(student); //Query API Query query = em.createQuery("Select s from Student s where s.name like ?"); query.setParameter(1, "James%"); List<Student> studentList = query.getResultList(); for(Student s :studentList){ System.out.println(s.getName()); } tx.commit(); em.close();
  • 21. } } Note that we do not have to map the entity class explicitly as these are scanned automatically based on the @Entity annotation. The source code can be downloaded from the attachment section down below. Hibernate Concepts Entity and Value Type Hibernate makes distinction between entity and value types. Entity types represent the objects that can be persisted to the database. They are the first class citizen in hibernate. Hibernate manages the life cycle of and entity. An entity also has an identifier which identifies the different instances uniquely. Value types are objects which are managed in the context of an entity. They live and die within the scope of an entity. This distinction comes because of Hibernate philosophy of promoting rich domain model. This means more classes per table. Let's say we have Student Table which contains the Address also Student table ID NAME CITY COUNTRY Now we can map this table to two class. One Entity and another value type Student (entity class) @Entity public class Student{ private Long id; private String name; private Address address;
  • 22. //Setters and getters Address (value class) public class Address{ private String city; private String country; //setters and getters } So we have got two classes for one table. Also the life of Address object is within the life scope of Student object.The Student object can live independently but an independent address object has no meaning unless it is associated with a Student object. Flushing Flushing is the process of propagating the changes from the Java layer to the database. Whenever the call is done for a save, hibernate does not issues the SQL automatically. It keeps on noting the changes and queues all the SQL. The SQL's are issued to database at appropriate time. This propagation of changes is known as flushing. The default mode for flushing is automatic, where hibernate identifies when to flush. The flushing is done in the following cases: When the transaction is committed. Before query execution so that the query sees the latest data in the database. When session.flush() is called explicitly. The flushing mode can be changed by calling session.setFlushMode with parameter FlushMode.COMMIT. In this case the flushing happens only When the transaction is committed. When session.flush() is called explicitly. Dirty Checking Hibernate automatically tracks the changes in the entities when they are in managed state and persists the changes to the database. Look at the following example
  • 23. //Get the session from the Session factory. In the first unit of work we persist the Student object Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx= session.beginTransaction(); Student student = new Student(); student.setName("oyeJava"); Long studentId = (Long)session.save(student); tx.commit(); session.close(); //Start another unit of work. Note that we fetch the same row that we have saved. //Now change the name of student object but do not call any save or update method. //Still hibernate will figure out that the object has changed and hibernate will //persist the changes to the datbase.The process of finding the changes is known as dirty checking also. session = HibernateUtil.getSessionFactory().openSession(); tx= session.beginTransaction(); Student student1 = (Student)session.get(Student.class, studentId); student1.setName("Again Java"); tx.commit(); session.close(); Whenever hibernate fetches or saves an object to the database, it keeps a snapshot of the object. At the point when hibernate goes to persist the changes, it loops through all the objects and matches it with the snapshot it has got.If it identifies that the state of an entity has changed from its snapshot it flushes those changes to the database. Hibernate Debugging
  • 24. Debugging Hibernate application tends to be tricky as there is a time lag between application issuing a calls on hibernate api and hibernate issuing SQL to the database.We will look into various strategies to look into how to debug hibernate. Configuration Enable show_sql property in the hibernate configuration file. In your hibernate.cfg,xml put the following <!-- Log out all the sql that hibernate is issuing to datbase. This is very useful for debugging --> <property name="show_sql">true</property> This will flush all the sql that hibernate issues to databae. For example in ((Hibernate Introduction with Annotation)) example you will see in the console Hibernate: insert into Student (STUDENT_ID, name) values (null, ?) Enable format_sql to format the generate sql. However this will take more space. Change in hibernate.cfg.xml <!-- Format the logged sql --> <property name="format_sql">true</property> In the console Hibernate: insert into Student (STUDENT_ID, name) values (null, ?) To understand the origin of SQL, hibernate can put comments which can be enabled by putting the following property in hibernate.cfg.xml
  • 25. <!-- Show comment --> <property name="use_sql_comments">true</property> In the console Hibernate: /* insert com.oyejava.Student */ insert into Student (STUDENT_ID, name) values (null, ?) Enabling log4j Enabling logging level in log4j.properties can provide more information about the internal of application. Copy the sample log4j.properties from hibernate core download at etc folder. Run the application and you will tons of information about internals of hibernate. Tweak the level in log4j.properties. Enabling log4j.logger.org.hibernate.type at debug level will show the bind parameters. Do the following in log4j.properties. The following line is already there, you have to uncomment it. log4j.logger.org.hibernate.type=TRACE In the console Hibernate: insert into Student (STUDENT_ID, name) values (null, ?) 16:04:15,440 DEBUG StringType:133 - binding 'oyeJava' to parameter: 1 Debugging Source The hibernate download comes with the source code. The src folder in the download has all the source. For hard to solve problems you can start digging into the source code itself. In eclipse you can do it as follows: Go to Project properties by right clicking on project name in navigator view and than click on Properties. Go to Java Build Path -> Source
  • 26. Click on Link Source In the Linked Folder location and pick the location of hibernate source till src In the folder name give a name which does not conflicts with your present source location. Click on Finish and than Ok. You can now put break point in the application and can go the hibernate code. Hibernate Tools Hibernate tool comes as an eclipse plugin. This has useful feature including HQL editor which helps in development. To install Hibernate Tool follow the steps : Check as per your eclipse version, the right version of tool at http://www.jboss.org/tools/download.html . You can either download or use the update mechanism. (Update mechanism is better if you are the only one. If you want to share it among the team members go via download mechanism.) I will follow the download mechanism to show the steps. Extract the download zip file. There will be two folders features and plugins. Copy the files inside features into eclipse/features. Similarly do for plugins. If eclipse is up, close it and restart. In eclipse click on Window->Open Perspective->Other. Click on hibernate. It will open the hibernate perspective. Hibernate Mapping Class The basic notion of ORM is mapping between class and table. A class is considered to be an entity when it gets the Entity annotation. Entity @Entity public class Student { We can provide a name to an entity. By default the name is the class name. We can give another name to entity so that conflicts do not occur because of same name entity sitting in different package @Entity(name="anotherStudent") public class Student {
  • 27. By default this entity gets mapped to a table with same name. If we want to specify the table name explicitly @Entity @Table(name="Student") public class Student { Dynamic SQL Generation Hibernate by default generates the SQL for CRUD right in the beginning. This also means that even if we just update one property of the entity, still the update is issued for all the properties. If we want hibernate to generate SQL at runtime only taking care of changed entity only than use Entity annotation coming from hibernate. Let's introduce a property in Student class age @Entity @Table(name="Student") public class Student { //Id will correspond the primary key in the database private Long id; protected String name; protected Integer age; //Getters and Setters ... public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } ...
  • 28. Persist the student by making a new Student object and setting show_sql true. Student student = new Student(); student.setName("oyeJava"); Long studentId = (Long)session.save(student); The SQL generated by hibernate as seen in console is insert into Student (STUDENT_ID, age, name) values (null, ?, ?) Note that though the age has not been set but still the SQL contains the age parameter. Now let's introduce the Entity annotation from Hibernate so that we ask hibernate to generate the SQL at runtime rather than using the pre generated CRUD statement //dynamicInsert - Include only those properties which are not null in inserting the data //dynamicUpdate - Include only those properties which have changed @Entity @org.hibernate.annotations.Entity( dynamicInsert=true, dynamicUpdate=true) public class Student { The SQL generated at console is insert into Student (name, STUDENT_ID) values (?, null) Note that the age field is absent. This is useful when the table has very large number of columns and modification and insertion is done only on smaller number of columns. Immutability When we know that an entity is not going to change at runtime. For example older messages fetched from database, than we can ask hibernate to not to do dirty checking for it. This also results in better performance. @org.hibernate.annotations.Entity( dynamicInsert=true,
  • 29. dynamicUpdate=true, mutable=false ) public class Student { Hibernate Mapping Identity Identity of an object is the property which is mapped to primary key of the row in the database. The id of the entity is mapped by @Id annotation @Entity @Table(name="Student") public class Student { //Id will correspond the primary key in the database private Long id; protected String name; ... //Id - Represents that it is a primary key column //GeneratedValue - How the key to be generated //column - Column to which this property is mapped @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="STUDENT_ID") public Long getId() { return id; } public void setId(Long id) { this.id = id; } ... Hibernate supports many identifier generation strategy which supports all the major databases
  • 30. Hibernate does not allows to change the Id once it has been set. It throws an exception if an attempt is made student = new Student(); Long studentId = (Long)session.save(student); //student.setId(80L); - This will throw an exception Right now JPA supports limited identifier generation strategy. So if the hibernate generation strategies need to be employed than do as follows: @Entity @org.hibernate.annotations.GenericGenerator( name="hibernate-native", strategy="native") public class Student{ private Long id; protected String name; @Id @GeneratedValue(generator="hibernate-native") @Column(name="STUDENT_ID") public Long getId() { return id; } It's possible to write one's own identifier generation strategy by implementing IdentifierGenerator interface. However try to use one of the existing generator as Hibernate already has very rich identifier generators. Hibernate Mapping Properties In this section we will look into how to map the different types of properties. All properties if mapped with annotation are by default persistent. This is different from when XML is used for mapping. In XML mapping, only the properties explicitly mapped are persistent.
  • 31. Transient If a property needs to be stopped from being persistent. @Transient public int getActive() { return active; } Now this property does not becomes part of persistent mechanism. The property resides only in the Java layer. Temporal Allow to map java.util.Date and java.util.Calender. In SQL the date are differentiated by whether it's a date, time or a timestamp. Timestamp has both date and time. However in Java the date is always a timestamp. It has all the information. So we have to deal with this mismatch also. //Options for TemporalType // - DATE // - TIME // - TIMESTAMP @Temporal(TemporalType.TIMESTAMP) public Date getBirthDate() { return birthDate; } Large Data Large data is characterized by whether it is a binary large data (BLOB) or character larger date (CLOB) Blob - byte[], Byte[] Clob - char[], Character[] BLOB and CLOB both are mapped with Lob annotation @Lob public byte[] getPicture() {
  • 32. return picture; } Enumeration Enumeration are type safe way of restricting the choice in Java. Let's say we have enum defined in Java as public enum StudentType { CURRENT, ALUMNI } to specify the usage of this enum in entity @Enumerated(EnumType.STRING) public StudentType getStudentType() { return studentType; } Enum Type can be String or Ordinal. If String is specified, in the database CURRENT or ALUMNI is stored. If ordinal is specified 0 or 1 is saved. If Enum Type is omitted ORDINAL is taken as default. Derived Properties Derived properties are useful to calculate formulas or derived values which is not stored in database but important for business purpose. @org.hibernate.annotations.Formula("(MARKS/TOTAL_MARKS)*100") public Long getPercentage() { return percentage } The value is evaluated while fetching the entity so it might be outdated at other times. It's the responsibility of the developer to keep it updated.The property appears in the SELECT statement only and does not participates in INSERT or UPDATE statement.Even SQL expression can be passed to the
  • 33. underlying database so there is a chance to build database dependency.SQL functions including SQL subselects can be used. Handling Generated Values In DDL we define defaults to many values like SYSDATE for timestamp which means if we do not give value from Java it is automatically generated.After saving if we want to refresh the object in Java layer, we will have to call a refresh on the object. The other way is that we can tell Hibernate to refresh the value automatically after an insertion. Make sure that you have dynamicInsert set to false otherwise null value will be inserted into the database. @Column(updatable= false, insertable = false) @org.hibernate.annotations.Generated (org.hibernate.annotations.GenerationTime.INSERT) public Double getPendingAmount() { return pendingAmount; } Embedded classes Embedded classes are useful for bringing fine domain modeling. We have one table but more classes mapped to it to bring rich domain model. Though Student table contains all the details for Student and his address, we will map it to two classes. Student Table Student_Id Name City Country Let's have city and country mapped to a different class Address. We put Embeddable annotation on it to tell that it will be used as an embedded property in an entity class @Embeddable public class Address { protected String city;
  • 34. protected String country; @Column(name = "ADD_CITY") public String getCity() { In the Student class private Address address; @Embedded public Address getAddress() { return address; } //Setter method By default this will mapped to ADD_CITY column name as mapped in Address. To get it mapped to CITY column as in Student table, we ill have to override the column name. @Embedded @AttributeOverride (name= "city",column = @Column(name="CITY")) public Address getAddress() { return address; } Now in this case we can navigate to Address object by holding a reference of Student object. But it's not possible to navigate from Address object to Student object. To build the bi directional navigation in Address entity In Address class @org.hibernate.annotations.Parent public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; }
  • 35. Hibernate Collection Mapping Hibernate supports collection mapping as value type. In Hibernate collection mapping, the collection are mapped into a separate table but are not exposed as entity on the Java side. Hibernate supports following collection interfaces as value type: java.util.Set – java.util.HashSet is used to store value. java.util.SortedSet – java.util.TreeSet is used to store value. java.util.List – java.util.ArrayList is used to store value. Preserves the position with an index column Bag semantics – java.util.ArrayList is used to store valre however the position is not preserved. java.util.Map – java.util.HashMap is used to store value. java.util.SortedMap – java.util.TreeMap is used to store value. Let‟s say we want to store Phones for a Student. There are more than one Phone for a Student. So we will have two tables corresponding to Student and Phone. However we do not want to expose Phone Table STUDENT STUDENT_ID ... Table PHONE STUDENT_ID NUMBER ... STUDENT_ID is the foreign key and PHONE table has no primary key. To map the Phone collection as a Set in the Student Entity class Student class ... @org.hibernate.annotations.CollectionOfElements(targetElement = java.lang.String.class) @JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID")) @Column(name="PHONE_NO")
  • 36. public Set<String> getPhones() { ... The lifecycle of Phone is tightly coupled to Student. Also Phone table is not exposed as an entity. If the Set need to be sorted ... @org.hibernate.annotations.CollectionOfElements(targetElement = java.lang.String.class) @JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID")) @Column(name="PHONE_NO") @org.hibernate.annotations.Sort(type=org.hibernate.annotations.SortType.NATURAL) public Set<String> getPhones() { ... A comparator can also be used for Sort type. To map the Phone collection as a list ... @org.hibernate.annotations.CollectionOfElements @JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID")) @org.hibernate.annotations.IndexColumn(name=“INDEX_POSITION", base =1) @Column(name="PHONE_NO") public List<String> getPhones() { return phones; } --- Here the index is mapped to a INDEX_POSITION column in the table and preserves the ordering. If the index is not given, this works like a Bag. Bag is a list but does not preserves the position. To map Phone as a map where PHONE_NAME will act as key and PHONE_NO as value from the PHONE table. To map it ... @org.hibernate.annotations.CollectionOfElements @JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))
  • 37. @org.hibernate.annotations.MapKey(columns = @Column(name="PHONE_NAME")) @Column(name="PHONE_NO") public Map<String,String> getPhones() { ... Here the Phone table is mapped directly as a collection. We can also expose Phone as a value object. In this case define Phone as a class @Embeddable public class PhoneValue { protected Student student; protected String name; protected String phoneNumber; @org.hibernate.annotations.Parent public Student getStudent() { return student; } ... Also in the above case we maintain a back pointer for Student so that we can navigate from Phone to Student. To define the collection of embedded object in Student class ... protected Collection<PhoneValue> phoneValues = new ArrayList<PhoneValue>(); @org.hibernate.annotations.CollectionOfElements @JoinTable(name = "Student_Phone_Value",joinColumns = @JoinColumn(name="STUDENT_ID")) @CollectionId(columns= @Column(name="STUDENT_PHONE_VALUE_ID"), type=@org.hibernate.annotations.Type(type="long"), generator="sequence") public Collection<PhoneValue> getPhoneValues() { return phoneValues; } ...
  • 38. Hibernate collection mapping is a way of mapping the collection table as values. The lifecycle of the the collections are tightly bound to the collection of the owning entity. Hibernate Relationship Mapping Hibernate relationship mapping takes care of mapping the relationship in the relational world. The relationship that exist in the relational world are: @OneToOne @OneToMany @ManyToOne @ManyToMany Though the notion of directionality is not present in relational world, it is relevant for the Java world. So we will have to handle in the Java world whether we want to build unidirectional or bidirectional relation. Please note the the need of unidirectional or bidirectional relationship should be governed by your need of domain. For example if we have a Student and Address table with One to One relationship between them. One To One Let's say we have Address and Student in its own table and we expose Address also as an entity. @Entity public class AddressEntity implements Serializable{ protected Long id; …. @Id @GeneratedValue @Column(name="ADDRESS_ID") public Long getId() { return id; } Map the relationship in the Student entity with directionality build from Student side In Student class
  • 39. ... private AddressEntity address; //Cascade Type defines that if the owning entity in this case Student is saved, than //whether the AddressEntity will also get saved. @OneToOne(cascade={CascadeType.ALL}) @JoinColumn(name="ADDRESS_ID") public AddressEntity getAddressEntity() { return address; } ... Also note the cascade type here. The cascade type defines whether the AddressEntity will get saved when we save Student. For example let's say the mapping in Student class, if we remove the Cascade type will be: ... private AddressEntity address; @OneToOne // comment out - (cascade={CascadeType.ALL}) @JoinColumn(name="ADDRESS_ID") public AddressEntity getAddressEntity() { return address; } ... Now let's try to save a Student and AddressEntity Student student = new Student(); AddressEntity add = new AddressEntity(); student.setAddressEntity(add); //If you try to save student, it will throw an exception as //it finds AddressEntity wired to it but AddressEntity is transient. //To persist the transient AddressEntity with the Student uncomment the CascadeType //session.save(student);
  • 40. We can make the primary key for both the related table same. It means that in the Address table the primary key and foreign key are same. In the Student class @OneToOne(cascade={CascadeType.ALL}) @PrimaryKeyJoinColumn public AddressEntity getAddressEntity() { return addressEntity; } In the above case the AddressEntity can be reached from Student but from AddressEntity you cannot reach to Student. Map the Student entity in the AddressEntity class ... protected Student student; @OneToOne(mappedBy="bankAccount") public Student getStudent() { return student; } ... Note that this relationship in the Java world does not makes any change to the relational world. In the case of bidirectional association, there is a notion of owning entity. The owning entity governs in what case the relationship will materialized in the database.The owning entity is the entity which is on the opposite or inverse side of mappedBy. In the case as the mappedBy is on the AddressEntity, the Student entity becomes the owning type. Now look at following piece of code Student student = new Student(); AddressEntity add = new AddressEntity(); //Map the relationship from AddressEntity side add.setStudent(student); //we will assume that CascadeType is All. session.save(student);
  • 41. If we look into the database, the Student and AddressEntity both are created in the database but the relationship is not build between Student and AddressEntity table. To fix the problem change the above code to Student student = new Student(); AddressEntity add = new AddressEntity(); //Map the relationship from Student side student.setAddressEntity(add); //we will assume that CascadeType is All. session.save(student); Now the relationship will be properly created as we have made the relationship from owning side. It's a good price to build the relationship from both side whenever the relationship is effected from one side. Student student = new Student(); AddressEntity add = new AddressEntity(); //Good Practice: Map the relationship on both side student.setAddressEntity(add); add.setStudent(student); //we will assume that CascadeType is All. session.save(student); For owning entity, you have to take care of following: If a AddressEntity has to be assigned to a different student, than unset the addressEntity on the original student and set it into the new student. For deleting a AddressEntity, unset it from the student object and than remove it from database calling remove method on entity manager. One To Many Let's have PhoneEntity table with one to Many relationship from Student.
  • 42. Student Table STUDENT_ID //Primary Key ... PhoneEntity table PHONE_ID //Primary Key STUDENT_ID //Foreign Key ... Now the PhoneEntity class looks like @Entity public class PhoneEntity implements Serializable{ protected int id; protected String number; @Id @GeneratedValue @Column(name="PHONE_ID") public int getId() { There is no reference to Student in PhoneEntity class, though the relationship is maintained in PhoneEntity table in database. Now to build the One to Many relationship in Student @OneToMany(cascade={CascadeType.ALL}) public Collection<PhoneEntity> getPhoneEntityList() { return phoneEntityList; } To save phone Entity the code would look like Collection<PhoneEntity> phoneList = new ArrayList<PhoneEntity>(); PhoneEntity p1 = new PhoneEntity(); p1.setNumber("100"); phoneList.add(p1);
  • 43. PhoneEntity p2 = new PhoneEntity(); p2.setNumber("200"); phoneList.add(p2); student.setPhoneEntityList(phoneList); We can tell hibernate that if an element is removed from a collection than delete it from database as this is the only reference to that entity. @OneToMany(cascade={CascadeType.ALL}) @org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN ) public Collection<PhoneEntity> getPhoneEntityList() { return phoneEntityList; } If we want the relationship data to be managed in a join table @OneToMany(cascade={CascadeType.ALL}) @JoinTable(name="STUDENT_PHONE",joinColumns={@JoinColumn(name="STUDENT_ID")}, inverseJoinColumns={@JoinColumn(name="PHONE_ID")}) public Collection<PhoneEntity> getPhoneEntityList() { return phoneEntityList; } Now let's see Many To One unidirectional relationship. Let's say we have a country table and Student is mapped to Country with Many to One relationship. Student Table STUDENT_ID //Primary Key COUNTRY_ID //foreign Key ... Country Table
  • 44. COUNTRY_ID //Primary Key ... Country Entity @Entity public class Country implements Serializable{ protected long id; protected String name; @Id @GeneratedValue @Column(name="COUNTRY_ID") public long getId() { return id; } ... Student Entity private Country country; @ManyToOne @JoinColumn(name="COUNTRY_ID") public Country getCountry() { return country; } Note that we are not using cascade here as normally the country is a master data and should not be created or deleted in the context of a Student. To save a Student Country country = new Country(); country.setName("India"); session.save(country); student.setCountry(country); Many to one and One to many are two sides of the same relationship. Let‟s convert Student and Country into bidirectional relationship.
  • 45. //the owning side of relationship is Many To One @OneToMany(mappedBy="country") public Collection<Student> getStudentList() { return studentList; } For persistence to work we have to call student.setCountry. If we just call country.getStudentList().add(student), The relationship will not change in the database. As a good practice Always wire both side of relationship. Many To Many ManyToMany relationship happens when both side maintains collection based relationship.Let‟s take an example of Student and Language they speak. A student can speak many language. Similarly a language can be spoken by many students Language Entity bean @Entity public class Language implements Serializable{ protected long id; protected String name; Student Bean @ManyToMany @JoinTable(name=“A_B",joinColumns={@JoinColumn(name=“C")}, inverseJoinColumns={@JoinColumn(name=“D")}) public Collection<Language> getLanguageList() { return languageList; } For Many to Many bidirectional Language Bean
  • 46. @ManyToMany(mappedBy="languageList") public Collection<Student> getStudentList() { return studentList; } For modifying the same ownership rule applies as we have seen in other bidirectional relationships. The collection can be fetched in certain order. E.g if we want to fetch the list of languages in certain order we can say on the Student side of relationship @ManyToMany @OrderBy(“name ASC”) @JoinTable(name="STUDENT_LANGUAGE", joinColumns={@JoinColumn(name="STUDENT_ID")}, inverseJoinColumns={@JoinColumn(name="LANGUAGE_ID")}) public List<Language> getLanguageList() { return languageList; } For descending order use name=DESC Hibernate Mapping Inheritance Inheritance is an important concept in Java but there is no counterpart in Relational world. There are some solutions is relational world but they are not widely used and also vendor specific. Hibernate provide some strategies to handle this situation where the inheritance hierarchy is mapped into the relational world. Let's have the java classes where we have a User class and Employee and Customer are inherited from it. The various strategies employed by hibernate to map this hierarchy to relational world is as follows: Single Table per class hierarchy – Single table has all properties of every class in the hierarchy. Table per concrete class – Each subclass has a table having all the properties of super class also. Table per subclass – Each class is mapped in its own table. There is separate table for super class and subclass.Table Single Table per class hierarchy
  • 47. In Single table per subclass, the union of all the properties from the inheritance hierarchy is mapped to one table. As all the data goes in one table, a discriminator is used to differentiate between different type of data. User (Base classe) //DiscriminatorColumn - Tells about the type of data //DiscriminatorValue - Is the data is representing User type, the value is "USER" @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="DISCRIMINATOR", discriminatorType=DiscriminatorType.STRING) @DiscriminatorValue("USER") @Table(name="BASIC_USER") public class User{ protected long id; protected String name; Customer class //There is no id column @Entity @DiscriminatorValue("CUST") public class Customer extends User{ protected double creditLimit; Employee class //There is no id column @Entity @DiscriminatorValue("EMP") public class Employee extends User{ protected String rank ... }
  • 48. The table structure would look like Basic_User Table ID NAME CREDIT_LIMIT RANK DISCRIMINATOR Now the objects can be saved polymorphically //User object referred by User type reference User user = new User(); user.setName("Superman"); session.save(user); Customer customer = new Customer(); customer.setName("Spiderman"); customer.setCreditLimit(1060); //User reference pointing to Customer object User user2 = customer; session.save(user2); Advantages of Single Table per class hierarchy Simplest to implement. Only one table to deal with. Performance wise better than all strategies because no joins or sub-selects need to be performed. Disadvantages: Most of the column of table are nullable so the NOT NULL constraint cannot be applied. Tables are not normalized. Table per concrete class
  • 49. In this case let's say our User class is abstract and Customer and Employee are concrete classes. So the table structure that comes out is basically one table for Customer and one table for Employee. The data for User is duplicated in both the tables. The User entity in this case is User @Entity @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public abstract class User{ protected long id; protected String name; @Id @GeneratedValue(strategy = GenerationType.AUTO) public long getId() { ... Customer class @Entity public class Customer extends User{ protected double creditLimit; ... This strategy is not popular and also have been made optional in Java Persistence API. Advantage: Possible to define NOT NULL constraints on the table. Disadvantage: Tables are not normalized. To support polymorphism either container has to do multiple trips to database or use SQL UNION kind of feature. Table per Sub class
  • 50. In this case all the classes are mapped to its own table. It's highly normalized but performance is not good. User class @Entity @Inheritance(strategy=InheritanceType.JOINED) @Table(name="BASIC_USER") public class User implements Serializable{ protected long id; protected String name; ... } Employee class @Entity @PrimaryKeyJoinColumn(name="EMPLOYEE_ID") public class Employee extends User{ protected String rank; ... } The derived class mapped table contain the foreign key which maps it to the base class. The table structure is as follows Basic_User Table ID NAME Employee table EMPLOYEE_ID // Acts both as primary key and foreign key. RANK
  • 51. Advantage: Tables are normalized. Able to define NOT NULL constraint. Disadvantage: Does not perform as well as SINGLE_TABLE strategy A comparison of three strategies is as follows: Table per Criteria Single Table Table per subclass concrete class One table for Data not normalized. each concrete Constraint for class. mandatory columns to Normalized. Not maintainable. be not nullable cannot Table Support Mandatory column constraint Change in base applied. can be applied class leads to Change in any subclass changes in all leads to change in tables of derived structure of Table class Discriminator Present Absent Absent Column Joins among table. For example simple SELECT. All data fetching Customer will require a is in one table. Using Retrieving join on Customer and User table. Separate Select or discriminator type, data If all user needs to be fetched Union Select individual types can be than it will put a join for all three selected tables Multiple. For User type one insert One insert or Updating and Single INSERT or on User table. For Customer type update for each Inserting UPDATE one insert on User table and subclass
  • 52. another on Customer table. JPA Support Mandatory Optional Which Strategy to Choose Usually the choice is between Single Table and Table per subclass strategy. Table per concrete class is optional in JPA and may hinder your portability later on.They also represent the two ends of the spectrum. Some rule of thumbs are: If there are many properties common in the base class and very less uncommon properties in derived class. Go for Single table strategy. However make sure your database architect is comfortable with nullable constraint not put on the properties of derived class. If there are too many uncommon properties, you might want to go for table per subclass strategy. Another criteria is the amount of polymorphic queries you do. If most of the time you fetch Customer and Employees separately you can go for Table per subclass as this will involve join only on two tables a time. However if you have requirements where you fetch User polymorphically most of the time, Single table strategy will give better performance. Inheriting From a non entity base class Let's say we want to put Audit information in many tables. We can make Audit as a base class and make our entities class to inherit from Audit class Audit class @MappedSuperclass public class Audit { protected Date updateDate; protected Date createDate; @Temporal(TemporalType.TIMESTAMP) public Date getCreateDate() { return createDate; }
  • 53. ... } User class @Entity @Table(name="BASIC_USER") //If we want to overried the column name than AttributeOverride is required @AttributeOverride(name="createDate",column=@Column(name="CREATE_DATE")) public class User extends Audit{ ... } Hibernate Persistent Context and Session The concept of Persistent Context and Session are central to the runtime behavior of Hibernate. Persistent Context is a run time memory area where Hibernate holds the references of objects and Session provides api to interact with the objects. Let's look them into one by one. Persistent Context At runtime whenever a session is opened and closed, between those open and close boundaries Hibernate maintains the object in a Persistence Context. Think of it like a first level runtime cache which hibernate controls. Hibernate does automatic dirty checking and transactional write-behind for the entity managed in Persistent Context. Hibernate guarantee a scope of Java object identity in this cache. Only one object instance representing a particular database row exists in the cache. Hibernate can extend the persistence context to span a whole conversation. Let's look at following piece of code. Here you can see the use of Session also. //Persistent Context 1 Starts Session session1 = HibernateUtil.getSessionFactory().openSession(); Student studentA = (Student)session1.get(Student.class, studentId); Student studentB = (Student)session1.get(Student.class, studentId); if(studentA == studentB){ System.out.println("Objects point to same refrence"); }
  • 54. session1.close(); //Persistent Context 1 Ends //Persistent Context 2 Starts Session session2 = HibernateUtil.getSessionFactory().openSession(); Student studentC = (Student)session2.get(Student.class, studentId); if(studentA == studentC){ System.out.println("Objects point to same refrence"); }else{ System.out.println("Objects do not point to same reference"); } session2.close(); //Persistent Context 2 Ends In the first case studentA and studentB will point to same object as Hibernate guarantees that against a same id only one object exist in the Persistent context. However in the second case studentA and studentC will be pointing to different objects as there is a different Persistent context. Hibernate does not maintains the guarantee beyond a Persistent Context Scope. Suppose after closing the session2, let's put all the objects in a set Set allStudents = new HashSet(); allStudents.add(studentA); allStudents.add(studentB); allStudents.add(studentC); The set will only have two objects. The good practice is to avoid using detached object in situation like above outside of a persistent context or objects coming from different persistent context. Also make sure that the hashCode() and equals() method are properly overridden. Important points about Persistent Context: Beware that hibernate keeps a snapshot of each persistent entity for dirty checking. Keep the size of your persistent context to minimum. Keep an eye to your sql logs. Avoid object graphs. Use session.evict(object) to clear big size objects once you are done with it. Use session.clear() when you want to remove all objects.
  • 55. Use session.setReadOnly(object,true) you can disable dirty checking for a particular instance. The biggest problem that comes with ORM solutions are performance problems and memory issues Session Hibernate provides api through Session object to handle database interaction task. The database interaction task are as follows: Basic CRUD operation Query Execution Control of Transaction Management of Persistent Context To make an object persistent, save is used Student tempStudent = new Student(); tempStudent.setName("Om Shanti Om"); session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); session.save(tempStudent); tx.commit(); session.close(); To retrieve the object, we can use either load or get session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); //Either use get or load to fetch the entity student = (Student)session.get(Student.class, studentId); //student = (Student)session.load(Student.class, studentId); tx.commit(); session.close();
  • 56. get() returns null if no database object for the id is found.load() throws ObjectNotFoundException. Also load method may return a proxy and tries to avoid hitting the database. session = HibernateUtil.getSessionFactory().openSession(); tx = session.beginTransaction(); Student loadStudent = (Student)session.load(Student.class, studentId); //The database hit happens here loadStudent.getName(); tx.commit(); session.close(); Hibernate automatically checks for the changes in the entity and flushes the changes to the database. session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); student = (Student)session.get(Student.class, studentId); student.setName("Abhishek"); //No explicit call is made to update the record in database. Still the changes //are flushed automatically tx.commit(); session.close(); Data can be removed by calling delete on Student loadStudent = (Student)session.load(Student.class, studentId); session.delete(student); An object has to be loaded in persistence context to use delete. The other option is to use bulk operations which can issue direct deletes.Hibernate can also roll back the identifier of any entity that has been deleted, it you enable the hibernate.use_identifier_rollback configuration option. The object can than be treated as transient object.
  • 57. After persistence context is closed, item becomes a detached instance. The detached object can be handled using update or merge.If there is already an instance of object in the persistence context an exception is thrown. Managing Detached Entities Detached entities can be managed again by calling update. //update to student done outside of persistent scope student.setName("abc"); session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); //Reattaching. Hibernate will always issue an update, //even if the object is not dirty //The update can happens after attaching. session.update(student); student.setAddress(…); tx.commit(); session.close(); The detached entity can be attached using lock //Modification to a detached entity session.setName("abc"); session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); //Reattaching. Lockmodes are NONE, READ, UPDATE. session.lock(student, LockMode.NONE); //It matters where changes are called. If changes are called before locking only, //the update is not issued student.setAddress("Pune");
  • 58. tx.commit(); session.close(); Merging Merging merges the detached instance with the managed instance. session.setName("oyejava"); session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); session.merge(student); tx.commit(); session.close(); Merging returns a new managed object. The detached instance remains detached. Merging includes all value typed properties and all additions and removals of elements to any collection. Usually it‟s better to discard the detached instance and continue the work with the managed entity. Hibernate Entities Life cycle The entities managed by Hibernate has a life cycle associated with them. Either you can make a new object in heap and save it into database or the data can be fetched from the database and given to user as database. The hibernate objects go through certain stages in the life cycle. Only entity objects participate in the life cycle. The value objects do not participate in the life cycle. The stages in the life cycle of an entity managed by Hibernate are as follows: Transient Objects When objects are created in the Java layer with new or similar operator and they have no corresponding record existing in database than these objects are termed as Transient objects. These objects exist in heap. The primary key attribute of this object is still not set. Transient objects are non transactional and in fact Hibernate has no knowledge of these objects at this point of time, Objects that are referenced only by other transient instances are, by default also transient. For an instance to
  • 59. transition from transient to persistent state or to go managed state, it requires either a call to persistence manger or the creation of a reference from an already persistent instance. Persistent Objects Persistent entity is again an object in heap but it has a valid database identity associate with it. The entity goes into persistent object by one of following means: Objects instantiated by application and then made persistent by calling one of the methods on the persistent manager. The objects become persistent when a reference is created from one of the persistent object. The entities retrieved from the database either by doing query, lookup or navigating the object graph. Persistent instances are always associated with a persistent context and Hibernate knows about them and may track them for dirty checking. Removed Object An object scheduled for deletion either by calling delete or because of orphan deletion of entities. One should not use the object in Java layer as the database record will be deleted at the end of session. A logic build around these objects might get into trouble. Detached Object The object in persistent state go into detached state after the persistent context is closed. Detached objects can be brought into other persistent context by reattachment or merging. Detached object still has a valid primary key attribute but it is no longer managed by Hibernate. Concept of owning entity in EJB and Hibernate The owning entity concept confuses many of the early adopters of Hibernate and JPA aka Entity beans in EJB3.0. We often confuse with the notion that we have to tell which of the entity is the owner.
  • 60. Before we delve deeper into this question let's understand why this whole notion of ownership comes into picture. The persistence provider gives us a lot of goodies in terms of saving us from handling low level sql handling and coding in terms of rows and columns. Even we get into this let's move one more level above and understand that ORM framework provide us a way to think in terms of objects. The thinking model with which Java programmers are comfortable with. OOAD is a very powerful notion as it helps us in thinking in terms of real world. ATM, Customer, Item, Bid, Auction become reusable notions in software world. However to provide that notion to Software world, ORM does a lot of dirty work (dirty checking !!!) for us. The most important feature that an ORM provides is transparent persistence. However to provide that the ORM framework does a lot of work under the hood. For example Hibernate keeps a copy of original entity from the database and before flushing does a dirty checking (Ahh I have heard this before). It will compare the values with the working entity and in case of changes will generate the SQL. Now let's take a concrete example of User and Address both having one to one and bidirectional relationship. That means we have Address reference from User and User reference from Address. (It does not matter whether we put the Fk on User side or Address side..Actually it matters with the kind of Sql the ORM tool will generate to materialize the relationship). Let's say for this example the foreign key is on User side. Now as a good Java Programmer whenever we have to change the address of a user we will do following:' user.setAddress(add); add.setUser(add); If you are an EJB2.1 guy than please look into the EJB3.0. It's more work but with very simple programming model and high portability. Now ORM frameworks will do the dirty checking and it will figure out that User and Address both has changed so it will issue a call to update both address and user. For User it will be update user set address_id =?
  • 61. and for address it will be similar call. So for almost all bidirectional relationship ORM framework will generate double update calls. This is a performance bottleneck Dr. Watson. So what we do. We as a programmer tell that which side is the owning, which means for the relationship to take into effect only one side of the dirty checking for the relationship needs to be done. If we put inverse or mapped by on address than for the relationship to take effect we need to do user.setAddress(add); If we just do add.setUser(add) the change will not be propagated into the database. However as a good programmer we should wire both side of the relationship. Now let's think for a moment can ORM framework cannot handle this is some way.Think over it, it can be done but will be a lot of bookkeeping and will complicate the frameworks a lot complex. Food for thought!!! Hibernate Query Language – HQL Session api's are used when an entity needs to be fetched from the database. To fetch list of records which might involve joins we have to use Hibernate Query Language (HQL). HQL queries are similar to SQL. They are written in OO way. Hibernate supports criteria queries also which are type safe way of writing queries. Hibernate supports the JPA QL also. Hibernate also supports issuing native SQL queries. The Query interface is used to build and execute queries. Fetching List To fetch a list In HQL: Query hqlQuery = session.createQuery("Select s from Student s"); List<Student> listStudent = hqlQuery.list(); //Iterating the list for(Student s: listStudent){ System.out.println(s.getName()); }
  • 62. Using Criteria: Criteria crit = session.createCriteria(PhoneEntity.class); List<PhoneEntity> phones = crit.list(); for(PhoneEntity p: phones){ System.out.println(p.getNumber()); } To restrict the list based on parameter HQL way: hqlQuery = session.createQuery ("from Student s where s.name like :name"); //The wild card can use used as similar to SQL hqlQuery.setString("name", "ab%"); List<Student> listStudent = hqlQuery.list(); Using Criteria: Criteria crit = session.createCriteria(Student.class); crit.add(Restrictions.ilike(“name", “ab”); List<Student> students = crit.list(); for(Student p: students ){ System.out.println(p.getName()); } Pagination Pagination is used when there are huge number of records and we want to fetch a subset of it. For example we want to display the list of students on front end so we might just want to fetch the 25 records which we want to display in third page. So we want the record which starts at 51th row and ends at 75th row HQL way:
  • 63. Query hqlQuery = session.createQuery("from Student s order by s.name asc"); hqlQuery.setFirstResult(51); hqlQuery.setMaxResults(25); List<Student> listStudent = hqlQuery.list(); Criteria way: Criteria crit = session.createCriteria(PhoneEntity.class); crit.addOrder(Order.asc("number")); crit.setFirstResult(51); crit.setMaxResults(25); List<PhoneEntity> phones = crit.list(); Binding Parameters It's always a good practice to bind the parameters rather than building the queries by String manipulation. It will protect from SQL injection also. For example do not do like Select s from Student s where s.name like "James%". Rather than use parameter binding. The parameters can be bound either using named parameter or positional parameter. Names parameter is better as it is more maintainable and readable. Named parameter binding: hqlQuery = session.createQuery("from Student s where s.name like :name"); //The parameter is given a name hqlQuery.setString("name", "James%"); List<Student> listStudent = hqlQuery.list(); Positional parameter binding: hqlQuery = session.createQuery("from Student s where s.name like ?");
  • 64. //The parameter is referred by position. For more than 1 parameter use number 0,1,2 //as thesequence used in query hqlQuery.setString0, "James%"); listStudent = hqlQuery.list(); Scrolling with database cursor Hibernate provides support for JDBC feature called scrollable result where the cursor is held on database. To open the curosr ScrollableResults itemCursor = session.createQuery(“from Student s).scroll(); The different functions to iterate using cursor //Go to first record itemCursor.first(); //Go to last record itemCursor.last(); //Go to next record itemCursor.next(); //Go to previous record itemCursor.previous(); Named Query Named query are queries where we give a name to it. These queries can bring performance as they can be cached. @NamedQuery{name=“findAllStudents”, query=“SELECT s from Student s where s.firstName LIKE :firstName”) Calling the query: Query query = em.createNamedQuery(“findAllStudents”);
  • 65. Polymorphic Queries Hibernate supports polymorphic query. For example suppose we have an inheritance structure on the OO side as mentioned in ((Hibernate Mapping Inheritance)).It does not matter whichever strategy you use, Hibernate will ensure to fetch the record as per polymorphism. If the query is "Select u from User u", hibernate will fetch all the records form User, Customer and Employee table. Expressions Hibernate supports the expression which can narrow down results as per some criteria. Some example of expression are //amount between 1 and 10 from Student s where s.pendingAmount between 1 and 10 //amount > 100 from Student s where s.pendingAmount > 100 //Only those students whose email is as mentioned from Student s where s.email in („a@a.com‟,‟b@b.com‟) //students whose email are not set where s.email is null //students whose mails are set where s.email is not null //student refers to a phone collection and the collection is not empty from Student i where i.phones is not empty Hibernate supports function also //lowering the name and than comparing from Student s where lower(s.name) like…
  • 66. //Concatenating the name and than comparing as the database is having only one name field //which contains both first and last name together from Student s where concat(s.firstName,s.lastName) like.. //Student has a collection of phone and has more than 2 phones. From Student s where size(s.phones) > 2 //current_date will calculate the date and return Select upper(s.name), current_date() from Student s Fetching Multiple Objects Multiple objects can be fetched as an object array. //It will return an Object [ ] with Student at index 0 and User at index 1 Select s , u from Student s, User u Scalar queries or Projection This is very useful in reporting. Fetching a lot of objects when we are looking for only some column data or want data from different tables leads to performance bottlenecks. In these cases it's better to use scalar queries as it fetched only required data Select s.name , s.pendingAmount from Student s This query will return an Object[].It‟s a scalar queries and the data fetched is not associated with persistence context. The fetched data is not managed for dirty states. Query Hints The flush mode can be disabled while executing the query. This can be useful when you do not want Hibernate to issue a flush before executing the query. For example if before executing the query you know that the results of the query is not going to be affected by the dirty states of entities in the session, for performance reason it's better to disable the flush. //Query way Query q = session.createQuery(queryString).setFlushMode(FlushMode.COMMIT);
  • 67. //Criteria way Criteria c = session.createCriteria(Student.class).setFlushMode(FlushMode.COMMIT); //JPA way Query q = em.createQuery(queryString).setFlushMode(FlushModeType.COMMIT); The cache mode can also be disabled while executing query.It tells hibernate to not to put any entities in the second level cache //Query way Query q = session.createQuery(queryString).setCacheMode(CacheMode.COMMIT); //Critera way Criteria c = session.createCriteria(Student.class).setCacheMode(CacheMode.COMMIT); //In JPA this is not supported as standard. If hibernate is the JPA provider than it can be used //using hibernate feature. Query q = em.createQuery(queryString).setHint (“org.hibernate.cacheMode”,org.hibernate.CacheMode.IGNORE); Dirty checking on the fetched objects can also be disabled. When you know that the fetched objects are not going to change it's better to disable the dirty checking. For example in case of fetching the list of objects for display purpose only //Query way Query q = session.createQuery(queryString).setReadOnly(true); //Criteria way Criteria c = session.createCriteria(Student.class).setReadOnly(true); //In JPA this is not supported as standard. //If hibernate is the JPA provider than it can be used using hibernate feature. Query q = em.createQuery(queryString).setHint(“org.hibernate.readOnly”, true); A timeout can also be passed as query hint which tells how long a long running query can be allowed
  • 68. //Query way Query q = session.createQuery(queryString).setTimeout(60); //Criteria way Criteria c = session.createCriteria(Student.class).setTimeout(60); //In JPA this is not supported as standard. //If hibernate is the JPA provider than it can be used using hibernate feature. Query q = em.createQuery(queryString).setHint(“org.hibernate.timeout”,60); Hibernate Shards Sharding is basically horizontal partitioning of data. If handled carefully, sharding can improve performance. For example let's say for a online mail provider, the mail subscribers can run into huge numbers. If all the rows of the database are sitting in the same server, it would hog a huge amount of memory. Sharding can help in horizontal partitioning of data. We can partition the records on the basic of continents. The continent information derived from the country information. So the rows belonging to North America and Asia would be sitting on different servers. If the queries are always continent specific most of the time, this partitioning will help in improving the performance and also indexing will be better. The care should be taken that if we have queries which involve going to different databases to fetch the result set, and if this is a prevalent scenario, sharding would result in degradation of performance. Hibernate Shards helps in dealing with horizontal partitioning of data. To use shards, let's assume we have a EmailUser table where the user data is saved. We will save the records alternately in two different database and will see that how hibernate shields us from the knowledge that it is talking to two different database. To make this tutorial, make a java project as outlined in Hibernate Introduction with Annotation. Also make sure Hypersonic jar is in the path. We will make a tutorial where the data is saved to two databases. The source code can be downloaded from the attachment section down below. Let's make the EmailUser class first. Note that it is a simple mapping class. @Entity public class EmailUser {
  • 69. private BigInteger id; private String name; private String continent; //The id is generated by using a Shard specific generator @Id @GeneratedValue(generator="EmailIdGenerator") @GenericGenerator(name="EmailIdGenerator", strategy="org.hibernate.shards.id.ShardedUUIDGenerator") @Column(name="ID") public BigInteger getId() { return id; } public void setId(BigInteger id) { this.id = id; } //Getters and setters for other properties ... } As we are interacting with two different databases, we need to provide two configuration file to Hibernate. If there are more than two databases, we have to provide same number of configuration files. Each file representing the details of a database. The first configuration file is usually the master file, where we provide all the details about other settings. Rest of the configuration files just contains the details of connection to database and shard specific id's. hibernate0.cfg.xml (First configuration file) <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  • 70. "http://hibernate.sourceforge.net/hibernate-configuration- 3.0.dtd"> <hibernate-configuration> <!-- note the different name --> <session-factory name="HibernateSessionFactory0"> <!-- Database connection settings --> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:hsql://localhost</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Second-level cache --> <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider/> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- property name="format_sql">true</property --> <!-- property name="use_sql_comments">true</property -->
  • 71. <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">create-drop</property> <!-- Shard specific confifuration --> <property name="hibernate.connection.shard_id">0</property> <property name="hibernate.shard.enable_cross_shard_relationship_checks"> true </property> </session-factory> </hibernate-configuration> The hibernate configuration for second database hibernate1.cfg (Second Configuration file) <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration- 3.0.dtd"> <hibernate-configuration> <!-- note the different name --> <session-factory name="HibernateSessionFactory0"> <!-- Database connection settings, this database is in memory --> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:file:1</property>
  • 72. <property name="connection.username">sa</property> <property name="connection.password"></property> <!-- SQL dialect - This tells the SQL grammer to be used --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <property name="hibernate.connection.shard_id">1</property> <property name="hibernate.shard.enable_cross_shard_relationship_checks"> true </property> </session-factory> </hibernate-configuration> In the true tradition of Hibernate, now we write the HibernateUtil class which is responsible for building sessionFactory public class HibernateUtil { private static SessionFactory sessionFactory; static{ try{ //Provide the master hibernate config AnnotationConfiguration prototypeConfig = new AnnotationConfiguration().configure("hibernate0.cfg.xml"); prototypeConfig.addAnnotatedClass(EmailUser.class); List<ShardConfiguration> shardConfigs = new ArrayList<ShardConfiguration>(); shardConfigs.add(buildShardConfig("hibernate0.cfg.xml")); shardConfigs.add(buildShardConfig("hibernate1.cfg.xml"));
  • 73. ShardStrategyFactory shardStrategyFactory = buildShardStrategyFactory(); ShardedConfiguration shardedConfig = new ShardedConfiguration(prototypeConfig, shardConfigs, shardStrategyFactory); sessionFactory = shardedConfig.buildShardedSessionFactory(); }catch(Throwable ex){ throw new ExceptionInInitializerError(ex); } } static ShardConfiguration buildShardConfig(String configFile) { Configuration config = new Configuration().configure(configFile); return new ConfigurationToShardConfigurationAdapter(config); } static ShardStrategyFactory buildShardStrategyFactory() { ShardStrategyFactory shardStrategyFactory = new ShardStrategyFactory() { public ShardStrategy newShardStrategy(List<ShardId> shardIds) { RoundRobinShardLoadBalancer loadBalancer = new RoundRobinShardLoadBalancer(shardIds); ShardSelectionStrategy shardSelection= new RoundRobinShardSelectionStrategy(loadBalancer); ShardResolutionStrategy shardResoultion = new AllShardsShardResolutionStrategy(shardIds); ShardAccessStrategy shardAccess = new SequentialShardAccessStrategy(); return new ShardStrategyImpl(shardSelection,