0% found this document useful (0 votes)
7 views

Step 7 - Hibernate

java

Uploaded by

Priyanka Agarwal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

Step 7 - Hibernate

java

Uploaded by

Priyanka Agarwal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 47

Asking is Good, so keep it up!!!

About Author

Sumit is a University Gold Medalist, holds master degree in computer application (MCA) &
have been working in IT industry more than eight years (since 2002).

He is a java-j2ee devotee and has extensive experience in eCommerce and EAI domain.

He also holds PG diploma in Operations and also Sun, RUP (Rational Unified Process) and webMethods
certified.

Who should read this?

People who don’t have time to go through entire thick book(s) but want to know all the aspects of ORM through
Hibernate programming.

Above all People who love java.

1|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!

Hibernate 3 (Object Relational Mapping API)


1. Introduction
• Applications can use the JDBC API to access data residing in a relational database management system
(RDBMS).
• However, even within an RDBMS environment, the actual syntax and format of the SQL statements may
vary depending on the particular database product.
• There is even greater variation with different types of persistent storage (flat files, xml, LDAP).
• Components such as bean-managed entity beans, session beans, servlets, and other objects like helpers for
JSP pages need to retrieve and store information from persistent stores.
• But including the connectivity and data access code within these components introduces a tight coupling
between the components and the data source implementation.

So the requirement is
• Components need to be transparent to the actual persistent store or data source implementation to provide
easy migration to different vendor products, different storage types, and different data source types.

Approach

• Use a Data Access Object (DAO) to abstract and encapsulate all access to the data source. The DAO
manages the connection with the data source to obtain and store data.

Understanding DAO
uses
encapsulates
Client EmployeeDAO
DB
Obtains/modifies
Creates/uses

EmployeeTO

Similar to EmloyeeDAO and Employee Transfer Object class, your application will be having
CustomerDAO DepartmentDAO OrderDAO AccountDAO

CustomerTO DepartmentTO OrderTO AccountTO

2|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!
/**************EmployeeDAO.java**********************/
package org.test.model;

import java.util.Collection;
import javax.sql.RowSet;

public class EmployeeDAO {


public int insertEmployee(EmployeeTO e) {
// code here
return 0;
}
public boolean deleteEmployee(int id) {
// code here
return false;
}
public EmployeeTO findEmployee(int id) {
// code here
return null;
}
public boolean updateEmployee(EmployeeTO e) {
// code here
return false;
}
public RowSet selectEmployeesRS(String condition) {
// code here
return null;
}
public Collection selectEmployeesTO(String condition) {
// code here
return null;
}
}
/**************EmployeeTO.java**********************/
package org.test.model;
import java.io.Serializable;

public class EmployeeTO implements Serializable {

private int employeeID;


private String name;
private String streetAddress;
private String city;

//getter setter methods


}

• Now this is clear that we will be having multiple DAO and TO classes.
• One more thing if we are designing to support multiple databases then these DAO must be created for
each type of database separately, rather then putting if-else inside the code.
• So, here it is a clear need of factory method and abstract factory pattern.

3|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!
So let’s start–
All databases specific DAO must implement same set of methods, to ensure this better to create interfaces
that will be implemented by DAO classes.
package org.test.model;

public interface IEmployeeDAO {

int insertEmployee(EmployeeTO e);


boolean deleteEmployee(int id);
EmployeeTO findEmployee(int id);
boolean updateEmployee(EmployeeTO e);
RowSet selectEmployeesRS(String condition);
Collection selectEmployeesTO(String condition);

package org.test.model.oracle;

public class OracleEmployeeDAO implements IEmployeeDAO {


public boolean deleteEmployee(int id) {
return false;
}
//other methods
}

Similarly for MySQL,


package org.test.model.mysql;

public class MySQLEmployeeDAO implements IEmployeeDAO{


public boolean deleteEmployee(int id) {
return false;
}
//other methods
}
Same thing we will do for customer, order, account, department etc. We will provide a db specific factory class
that will provide underlying DAOs.

OracleDAOFactory

OracleCustomerDAO OracleOrderDAO OracleEmployeeDAO OracleDepartmentDAO

implements

ICustomerDAO IOrderDAO IEmployeeDAO IDepartmentDAO

implements
MySQLCustomerDAO MySQLOrderDAO MySQEmployeeDAO MySQDepartmentDAO

MySQLDAOFactory

4|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!
All database specific DAO factories must provide their specific DAO, so they all must have same set of
methods. Again need of some abstraction. We can use either interface or abstract class.

/*****************DAOFactory**********************/
package org.test.model;

import org.test.model.mysql.MySQLDAOFactory;
import org.test.model.oracle.OracleDAOFactory;

public abstract class DAOFactory {

// List of DAO types supported by the factory


public static final int MYSQL = 1;
public static final int ORACLE = 2;
public static final int SQLSERVER = 3;

// There will be a method for each DAO that can be


// created. The concrete factories will have to

5|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!
// implement these methods.
public abstract IEmployeeDAO getEmployeeDAO();
public abstract IAccountDAO getAccountDAO();
public abstract IOrderDAO getOrderDAO();

public static DAOFactory getDAOFactory(int whichFactory) {

switch (whichFactory) {
case MYSQL:
return new MySQLDAOFactory();
case ORACLE:
return new OracleDAOFactory();
// ...
default:
return null;
}
}
}
/*****************OracleDAOFactory**********************/
package org.test.model.oracle;

public class OracleDAOFactory extends DAOFactory {

@Override
public IAccountDAO getAccountDAO() {
return new OracleAccountDAO();
}
public IEmployeeDAO getEmployeeDAO() {
// TODO Auto-generated method stub
return new OracleEmployeeDAO();
}
public IOrderDAO getOrderDAO() {
// TODO Auto-generated method stub
return new OracleOrderDAO();
}

// method to create oracle connections


public static Connection createConnection() {
// Use DRIVER and DBURL to create a connection
// Recommend connection pool implementation/usage
return null;
}

Now we are ready to use our full fledged DAO


DAOFactory oracleDF = DAOFactory.getDAOFactory(DAOFactory.ORACLE);
IEmployeeDAO employeeDAO = oracleDF.getEmployeeDAO();
EmployeeTO emp = new EmployeeTO();
emp.setEmployeeID(1);
emp.setName("Sumit Agarwal");
//insert the Employee
employeeDAO.insertEmployee(emp);
So, now it should be very much clear that, what DAO pattern is and when it is used through factory method and
abstract factory pattern it helps us to support multiple databases comfortably.

6|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!

Object Relational Mapping

• A DAO can use an ORM framework for persistence tasks.


• ORM framework is written to reduce the efforts done by DAO classes, like database connectivity,
constructing sql queries etc.
• ORM also improve the performance of DAO layer by providing caching, query optimization etc.
• Even ORM take care of database independency that’s why we do not require using factory method and
abstract factory pattern at DAO layer for achieving the same.
• DAO was 2 step approach, ORM will be introduced as a 3rd step, see the figure below.
• ORM will provide n number of features that we will see shortly.

Hibernate is an ORM framework that provides APIs (java classes) to achieve the above stated tasks.

There are other options also TopLink, iBatis, JDO, EJB-Entity Beans etc but hibernate is much more powerful
and simple to use.

Using Hibernate – 4 step process


We want to persist a record that keep the information about a employee through Hibernate.
Step 1 – Entity class need to be persisted  Employee.java ~= EmployeeTO.java

Step 2 – Hibernate requires a mapping file (employee.hbm.xml), that keep the information like table belongs to
this employee class, column mapping and association of this entity with other existing entities.

Step 3 – framework configuration file (hibernate.cfg.xml) keeping the information about the database
connection properties, mapping files locations of entities created in step 2 etc.

Step 4 – client program where we will take Hibernate’s SessionFactory and Session then will call save(),
update() etc. method to perform persistency.

7|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!
Note – Required Jars
antlr.jar, cglib.jar, asm.jar, asm-attrs.jars, commons-collections.jar, commons-logging.jar, hibernate3.jar, jta.jar,
dom4j.jar, log4j.jar

You may require more or less jars, depending on the hibernate release you are using.

Step 1 – Person.java
package org.test; Person is a POJO – Plain Old Java Object
public class Person { General Expectation-
1. follow java bean naming convention
private long personID; 2. put a identifier field to determine the
private String name;
private byte age;
object uniquely
3. Object of this class will represent one
public long getPersonID() { row of the table.
return personID; 4. Classes can be related to one another
} (association, aggregation etc.). We will
public void setPersonID(long personID) {
this.personID = personID; see defining relationship (one-to-one,
} one-to-many, many-to-many) in great
public String getName() { detail shortly. ;-)
return name;
}
E.g. Person POJO will have one-to-many
public void setName(String name) {
this.name = name; relationship with Order POJO
}
public byte getAge() { So needless to say we will make POJO classes
return age; for entities need to be persisted.
}
public void setAge(byte age) {
this.age = age;
}
} hbm – hibernate mapping file
Step 2 – person.hbm.xml
<?xml version="1.0"?>
1. define the POJO matched to which db
<!DOCTYPE hibernate-mapping PUBLIC table
"-//Hibernate/Hibernate Mapping DTD 3.0//EN" 2. define POJO property name matched
"http://hibernate.sourceforge.net/ with which column name in DB
hibernate-mapping-3.0.dtd"> 3. most important, id field and how this id
<hibernate-mapping>
<class name="org.test.Person"
will be generated
table="employee" native – db based next number generation. It
dynamic-insert="true" can be auto_increment for mysql and so on.
dynamic-update="true" > sequence – we can provide sequence name
<id name=" personID" column="id"> assign – our program will provide this id
<generator class="native" />
</id> value, instead of generating from database
<property name="name" type="java.lang.String" 4. dynamic-update="true" tells only
column="name" /> the changed fields should be
<property name="age" type="byte" column="age"/> consider
</class> 5. dynamic-insert = “true” tells
</hibernate-mapping> only non-default values shoulb be
consider

8|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!
Step 3 – hibernate.cfg.xml
<?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">
com.mysql.jdbc.Driver
Database connection parameter
</property>
<property name="connection.url">
jdbc:mysql://127.0.0.1:3306/test
</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect --> Dialect helps hibernate to understand
<property name="dialect"> the database capabilities like it
org.hibernate.dialect.MySQLDialect support sequence or not
</property>
<!-- Enable Hibernate's automatic session context management -->
<!—-It tell hibernate that is is being used in a non managed environment e.g.
no application server. Then Hibernate manage transaction and keep track of
threads, session etc. -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">
org.hibernate.cache.NoCacheProvider You need not to create
</property> tables in database,
<!-- Echo all executed SQL to stdout --> hibernate will do it for
<property name="show_sql">true</property> you. But don’t forget to
<!-- Drop and re-create the database schema on startup --> comment this after first
<property name="hbm2ddl.auto">create</property> run, otherwise you know
<mapping resource="org/test/person.hbm.xml" /> every time tables will
</session-factory> get dropped.
</hibernate-configuration> Mapping resource configuration those
want persistency
Step 4 – client program(s).
package org.test;
public class Client {
public static void main(String[] args) {
PersonDAO pDAO = new PersonDAO();
Person p = new Person();
p.setName("sumit agarwal");
p.setAge((byte) 28);
// creating a record
long id = pDAO.insertPerson(p);
System.out.println("Person created with id " + id);

// deleting the person


pDAO.deletePerson(p);
// reading a record
Person person = pDAO.getPerson(1);
System.out.println("Object loaded " + person.getName());
}
}
//supporting classes used in the client program

//DAO class now using ORM (3rd point in above diagram) ;)

9|Sumit Agrawal | Technical Architect | MCC Retail COE


Asking is Good, so keep it up!!!

package org.test;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.test.util.HibernateUtil;
public class PersonDAO {
public long insertPerson(Person p) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
Long id = (Long) session.save(p);
transaction.commit();
return id.longValue();
}
public boolean updatePerson(Person p) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
session.update(p);
transaction.commit();

return true;
}
public boolean deletePerson(Person p) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
session.delete(p);
transaction.commit();

return true;
}
public Person getPerson(long id) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
Person p = (Person) session.load(Person.class, new Long(id));

return p;
}
public List getAllPerson() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();

// Execute the HQL query on the data base. The HQL query here
// is equivalent of the "select * from employee" SQL. In HQL we never
// refer to tables. Only the name of the Class is refered to
List result = session.createQuery("from org.test.Person").list();
return result;
}

10 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

//HibernateUtil.java
package org.test.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {


private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure()
.buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
Output 1 – Before putting log4j.xml
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into employee (name, age) values (?, ?)
Person created with id 17
Hibernate: delete from employee where id=?
Hibernate: select person0_.id as id0_0_, person0_.name as name0_0_, person0_.age as
age0_0_ from employee person0_ where person0_.id=?
Object loaded sumit agarwal

Note For Removing above warning put log4j.xml with classes or bin folder
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %c{1} - %m%n" />
</layout>
</appender>
<root>
<priority value="debug" />
<appender-ref ref="console" />
</root>
</log4j:configuration>

Output 2 – After putting log4j.xml


INFO Environment - Hibernate 3.2.5
DEBUG -------
-------------------------------------------------------------
-------------------------------------------------------------
Object loaded sumit agarwal

So how easy it is to use hibernate ;-)

11 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
How we communicated with hibernate-

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


Transaction transaction = session.beginTransaction();
Long id = (Long) session.save(p); //one of the CRUD operation
transaction.commit();

How we can take out complete list of Person persisted into database-
List result = session.createQuery("from org.test.Person").list();

Hibernate Data Types

12 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

Mapping Relationships– the one of the challenging thing in Hibernate or any ORM ;-)
One-to-One

We can see above UML in several ways-


1. User entity keeps Address value
2. User entity has one-to-one relationship with Address entity

Hibernate makes the following essential distinction:

■ an object of entity type has its own database identity (primary key value). An entity has its own lifecycle; it
may exist independently. Examples are User, Item, and Category.
An object reference to an entity instance is persisted as a reference in the database (a foreign key value).

■ an object of value type has no database identity; it belongs to an entity instance and its persistent state is
embedded in the table row of the owning
So let’s work on 1st option “User entity keeps Address value”

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"

<hibernate-mapping package="org.test.model" default-access="field">

<class name="User" table="USERS">


<id name="id" type="long" column="USER_ID">
<generator class="native" />
</id>
<property name="name" type="string" column="NAME" length="255" not-null="true" />
<property name="email" type="string" update="false">
<column name="EMAIL" length="255" not-null="true" unique="true" />
</property>
<property name="password" type="string" column="PASSWORD" length="12" not-null="true" />
<property name="created" column="CREATED" type="timestamp" update="false" not-null="true" />

<component name="address" class="Address">


<property name="street" type="string" column="STREET" length="255" />
<property name="zipcode" type="string" column="ZIPCODE" length="16" />
<property name="city" type="string" column="CITY" length="255" />
</component>

</class>
</hibernate-mapping>

13 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

When you will generate table using hibernate hbm2ddl.auto service


<property name="hbm2ddl.auto">create</property> Note – See in hibernate.cfg.xml

Yes, when you will configure a value type using <component> its persistent state will be embedded
in the table row of the owning.

Now suppose a user has three different addresses, home, shipping and billing.
Keeping individual columns in USERS table will be an overhead so why not to create a separate table for
Address and keep the USER_ID in this as a foreign-key.

<join table="ADDRESS" optional="true">


<key column="USER_ID" foreign-key="FK_BILLING_ADDRESS" />
<component name="billingAddress" class="Address">
<property name="street" type="string" column="billing_STREET" length="255" />
<property name="zipcode" type="string" column="billing_ZIPCODE" length="16" />
<property name="city" type="string" column="billing_CITY" length="255" />
</component>
<component name="homeAddress" class="Address">
<property name="street" type="string" column="home_STREET" length="255" />
<property name="zipcode" type="string" column="home_ZIPCODE" length="16" />
<property name="city" type="string" column="home_CITY" length="255" />
</component>
<component name="shippingAddress" class="Address">
<property name="street" type="string" column="shipping_STREET" length="255" />
<property name="zipcode" type="string" column="shipping_ZIPCODE" length="16" />
<property name="city" type="string" column="shipping_CITY" length="255" />
</component>
</join>

14 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Now the USERS and new ADDRESS table will look like this.

Uni-directional and Bi-directional


Notice that, in this example, you model the composition association as unidirectional. You can’t navigate from
Address to User. Really you want to make it bidirectional?
Add this in component mapping <parent name="user"/>

public class User implements Serializable { public class Address implements


Serializable {
private Long id = null; private String street;
private String email; private String zipcode;
private String name; private String city;
private String password; private User user;
private Date created = new Date();
//getter setter
private Address homeAddress; }
private Address billingAddress;
private Address shippingAddress;

//getter setter
}

15 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Now Address class is having its own table in db, we can get the User object from Address after making it
bidirectional. But Still Address is value type, Should we promote it to entity type??

So let’s work on 2nd option - User entity has one-to-one relationship with Address entity

Above used <component> approach for one-to-one relationship was the simplest approach but what if we want to
make Address as a entity type. Because if it is an entity type then it will be having its own mapping file
(address.hbm.xml) and not only User other class can also have references of Address (shared reference).

e.g. Our Shipment wants to refer a row in address table (delieveryAddress)

public class Shipment implements


Serializable {

private Long id = null;

private Address deliveryAddress;

private Item auction;

private User buyer;


private User seller;

private int inspectionPeriodDays;

private Date created = new Date();

Approach 1 – Shared primary Keys (primary key one-to-one association)

Suppose we have created a USER


User newUser = new User();
Address shippingAddress = new Address();
newUser.setShippingAddress(shippingAddress);
session.save(newUser);

if Address table got the same primary-key, that is generated for the user then we can link User and Address by
this shared primary key.
Step 1 - map the association in User.hbm.xml:
<one-to-one name="shippingAddress" class="Address" cascade="save-update"/>

You add a cascading option because, If a User instance is made persistent, you usually also want its shippingAddress to
become persistent.
Step 2 – Special ID generator, so that it should get the same PK, as created for the User (address.hbm.xml)
<class name="Address" table="ADDRESS">
<id name="id" column="ADDRESS_ID">
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
...
<one-to-one name="user" class="User" constrained="true"/>
</class>

16 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

Note - constrained="true", adds a foreign key constraint linking the primary key of the ADDRESS table to the
primary key of the USERS table.

Now This Address_ID will be equal to USER_ID.

Approach 2 – One-to-one foreign key associations


Instead of sharing a primary key, two rows can have a foreign key relationship.

Step 1 – you now add a SHIPPING_ADDRESS_ID column in the USERS table:


<class name="User" table="USERS">
<many-to-one name="shippingAddress" class="Address" column="SHIPPING_ADDRESS_ID"
cascade="save-update" unique="true"/>
</class>
The mapping element in XML for this association is <many-to-one>—not <one-to-one>, as you might have expected. The
reason is simple: You don’t care what’s on the target side of the association, so you can treat it like a to-one association
without the many part. All you want is to express “This entity has a property that is a reference to an instance of another entity”
and use a foreign key field to represent that relationship.

Note - By making the SHIPPING_ADDRESS_ID column unique, you declare that a particular address can be referenced by at
most one user, as a shipping address.

With several foreign key columns (let’s say you also have unique HOME_ADDRESS_ID and BILLING_ADDRESS_ID), you can
reference the same address target row several times.

Step 2 – address.hbm.xml
<one-to-one name="user" class="User" property-ref="shippingAddress"/>
You tell Hibernate that the user property of the Address class is the inverse of a property on the other side of the association.
You can now call anAddress.getUser() to access the user who’s shipping address you’ve given. There is no additional
column or foreign key constraint; Hibernate manages this pointer for you.

Approach 3 – Mapping with a join table


In the database schema, you add an intermediate link table called USER_SHIPMENT_ADDRESS. This table contains the primary
keys of the both table.

Step 1 – add mapping to user.hbm.xml


<join table="USER_SHIPMENT_ADDRESS" optional="true">
<key column="USER_ID" />
<many-to-one name="shippingAddress" column="ADDRESS_ID" not-null="true"
unique="true" />
</join>
Similarly, we can make more intermediate table for home and billing address. But as the
related tables will grow the number of join table will also grow. That is not good.

This completes our discussion of one-to-one association mappings. To summarize, use a shared primary key association if one of the
two entities seems more important and can act as the primary key source. Use a foreign key association in all other cases, and a hidden
intermediate join table when your one-to-one association is optional.

17 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
One-to-many (Value type) –
Remember that value-typed classes don’t have identifiers or identifier properties. The lifespan of a value-type instance is
bounded by the lifespan of the owning entity instance. A value type doesn’t support shared references.

Many side – represents a collection. Without extending Hibernate, you can choose from the following collections:
• A java.util.Set is mapped with a <set> element. Initialize the collection with a java.util.HashSet. The
order of its elements isn’t preserved, and duplicate elements aren’t allowed. This is the most common
persistent collection in a typical Hibernate application.
• A java.util.SortedSet can be mapped with <set>, and the sort attribute can be set to either a comparator or
natural ordering for in-memory sorting. Initialize the collection with a java.util.TreeSet instance.
• A java.util.List can be mapped with <list>, preserving the position of each element with an additional
index column in the collection table. Initialize with a java.util.ArrayList.
• A java.util.Collection can be mapped with <bag> or <idbag>. Java doesn’t have a Bag interface or an
implementation; however, java.util.Collection allows bag semantics (possible duplicates, no element
• order is preserved). Hibernate supports persistent bags (it uses lists internally but ignores the index of the
elements). Use a java.util.ArrayList to initialize a bag collection.
• A java.util.Map can be mapped with <map>, preserving key and value pairs. Use a java.util.HashMap to
initialize a property. A java.util.SortedMap can be mapped with <map> element, and the sort attribute
canbe set to either a comparator or natural ordering for in-memory sorting. Initialize the collection with a
java.util.TreeMap instance.
• Arrays are supported by Hibernate with <primitive-array> (for Java primitive value types) and <array>
(for everything else). However, they’re rarely used in domain models, because Hibernate can’t wrap array
properties.You lose lazy loading without bytecode instrumentation, and optimized dirty checking,
essential convenience and performance features for persistent collections.

Suppose that sellers in online auctioning application are able to attach images to Items. An image is accessible
only via the containing item; it doesn’t need to support associations from any other entity in your system. The
application manages the collection of images through the Item class, adding and removing elements. An image
object has no life outside of the collection; it’s dependent on an Item entity.

Approach 1 - Mapping a set (Highly prefered approach)


The simplest implementation is a Set of String image filenames. First
Step 1 – Add a collection property to the Item class:
public class Item {
private Long id = null;
private Set images = new HashSet();
public Set getImages() {
return this.images;
}
public void setImages(Set images) {
this.images = images;
}
}
Step 2- <set> mapping in item.hbm.xml
<class name="Item" table="ITEMS">
<id name="id" type="long" column="ITEM_ID">
<generator class="native" />
</id>
<set name="images" table="ITEM_IMAGE">
<key column="ITEM_ID" />
<element type="string" column="FILENAME" not-null="true" />
</set>
</class>

18 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
A new table will be get created for <set> entry

Note - The <element> tag declares this collection as a collection of value type instances—in this case, of strings.

Approach 2 - Mapping an identifier bag


An unordered collection that permits duplicate elements is called a bag. The Java Collections framework doesn’t include a bag
implementation.

Step 1 – change Set interface with Collection interface


private Collection images = new ArrayList();

Step 2 – Map the collection in Hibernate with a standard <bag> or <idbag> element. Hibernate has a built-in
PersistentBag that can deal with lists; however, consistent with the contract of a bag, it ignores the position of elements in
the ArrayList.
<idbag name="images" table="ITEM_IMAGE">
<collection-id type="long" column="ITEM_IMAGE_ID">
<generator class="hilo" />
</collection-id>
<key column="ITEM_ID" />
<element type="string" column="FILENAME" not-null="true" />
</idbag>

Note - You also have to modify the collection table to permit duplicate FILENAMEs; the table needs a different primary key. An
<idbag> mapping adds a surrogate key column to the collection table

19 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Approach 3 Mapping a list
Step1 – Change Collection interface to List
private List images = new ArrayList();

Step 2 – Map the collection as a <list>


A <list> mapping requires the addition of an index column to the collection table. The index column defines the position of
the element in the collection. Thus, Hibernate is able to preserve the ordering of the collection elements.
<list name="images" table="ITEM_IMAGE">
<key column="ITEM_ID" />
<list-index column="POSITION" />
<element type="string" column="FILENAME" not-null="true" />
</list>

Approach 4 – Mapping a map


suppose that the images for an item have user-supplied names in addition to the filename. One way to model this in Java is a map,
with names as keys and filenames as values of the map.
Step 1 - private Map images = new HashMap();
Step 2 - Map the collection as a <map>
<map name="images" table="ITEM_IMAGE">
<key column="ITEM_ID" />
<map-key column="IMAGENAME" type="string" />
<element type="string" column="FILENAME" not-null="true" />
</map>

20 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Approach 5 Sorted and ordered collections

Big Note - A sorted collection is sorted in memory using a Java comparator. An ordered collection is ordered at the database
level using an SQL query with an order by clause.
Step 1 - private SortedMap images = new TreeMap();
Step 2 – <map> entry in item.hbm.xml
<map name="images" table="ITEM_IMAGE" sort="natural">
<key column="ITEM_ID" />
<map-key column="IMAGENAME" type="string" />
<element type="string" column="FILENAME" not-null="true" />
</map>
• By specifying sort="natural", you tell Hibernate to use a SortedMap and to sort the image names according to
the compareTo() method of java.lang.String.
• If you need some other sort algorithm (for example, reverse alphabetical order), you may specify the name of a class that
implements java.util.Comparator in the sort attribute.
sort="org.test.util.comparator.ReverseStringComparator"
• A java.util.SortedSet (with a java.util.TreeSet implementation) is mapped like this:
<set name="images" table="ITEM_IMAGE"sort="natural">
<key column="ITEM_ID"/>
<element type="string" column="FILENAME" not-null="true"/>
</set>
• For sorting elements on the database side, not in memory. Replace sort attribute with order-by.
order-by="IMAGENAME asc" or can use sql function also
order-by="lower(FILENAME) asc"

21 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Approach 6 - What if Image contains more properties instead of only filename? We have to write a class that will hold these
properties
Step 1 - Writing the component class
public class Image implements Serializable {
private String name;
private String fileName;
private int sizeX;
private int SizeY;
}
Note – You must implement equals() (and hashCode()) and compare the name, filename, sizeX, and sizeY
properties. Because Set, Map internally use these methods to identify uniqueness and hash bucket etc. Till we were using
filename that was String and String class already providing implementation of these methods.
Step 2 – The only difference is the use of <composite-element> instead of an <element>
<set name="images" table="ITEM_IMAGE" order-by="IMAGENAME asc">
<key column="ITEM_ID" />
<composite-element class="Image">
<property name="name" column="IMAGENAME" not-null="true" />
<property name="fileName" column="FILENAME" not-null="true" />
<property name="sizeX" column="SIZEX" not-null="true" />
<property name="sizeY" column="SIZEY" not-null="true" />
</composite-element>
</set>
In this case, No column in a composite primary key can be nullable because all make a composite primary key.

• For Bidirectional mapping add <parent name="item"/> in <composite-element> and add Item item;
property in Image.java
• Another way to switch to a different primary key is a map. You can remove the name property from the Image class
and use the image name as the key of a map:
<map name="images" table="ITEM_IMAGE" order-by="IMAGENAME asc">
<key column="ITEM_ID"/>
<map-key type="string" column="IMAGENAME"/>
<composite-element class="Image">
<property name="fileName" column="FILENAME" not-null="true"/>
<property name="sizeX" column="SIZEX"/>
<property name="sizeY" column="SIZEY"/>
</composite-element>
</map> (The primary key of the collection table is now a composite of ITEM_ID and IMAGENAME.)

22 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
one-to-many/many-to-one (Entity Type)
Remember entity type has its own database identity (primary key value). An entity has its own lifecycle; it may
exist independently. An object reference to an entity instance is persisted as a reference in the database (a
foreign key value) and it can be shared (shared references).

one-to-many – one item can have no, 1 or multiple Bids


many-to-one – Reversely, many bids for one item

Hey Don’t be lost ;-) one-to-one for value and entity type we have covered first, one-to-many for value type we
have done recently, one-to-many/many-to-one for entity type we are going to cover shortly and many-to-many
we will cover it later. Hope you are not running with broken links. Latterly we will take several real life scenarios
for practice all these association.
public class Bid { public class Item {
private Long id = null;
private Long id;
private Item item; private Set bids = new HashSet<Bid>();
//getter-setter private SortedMap images = new TreeMap();
} //getter-setter

-Unidirectional many-to-one association //a convenient method


public void addBid(Bid bid) {
<many-to-one name="item" column="ITEM_ID" bid.setItem(this);
class="Item" not-null="true" /> bids.add(bid);
}
}
<set name="bids" inverse=”true”>
<key column="ITEM_ID" />
<one-to-many class="Bid" />
</set>
If you compare this with the collection mappings earlier, you
see that you map the content of the collection with a different
element, <one-to-many>. This indicates that the collection
contains not value type instances, but references
to entity instances.

Big problem - we have two different unidirectional associations mapped to the same foreign key column. What side controls
that column? At runtime, there are two different in-memory representations of the same foreign key value: the item property of
Bid and an element of the bids collection held by an Item. Suppose the application modifies the association, by, for example,
adding a bid to an item in this fragment of the addBid() method:
bid.setItem(item);
bids.add(bid);

This code is fine, but in this situation, Hibernate detects two changes to the in memory persistent instances.
Without the inverse attribute, Hibernate tries to execute two different SQL statements, both updating the same foreign key
column, when you manipulate the link between two instances. By specifying inverse="true", you explicitly tell Hibernate
which end of the link it should not synchronize with the database.
• If you only call anItem.getBids().add(bid), no changes are made persistent!!! You get what you want only if the
other side, aBid.setItem(anItem), is set correctly.
Can you switch the inverse side? The <many-to-one> element doesn’t have an inverse attribute, but you can map it with
update="false" and insert="false" to effectively ignore it for any UPDATE or INSERT statements. The collection
side is then noninverse and considered for insertion or updating of the foreign key column.

23 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Transitive persistence
When you instantiate a new Bid and add it to an Item, the bid should become persistent automatically. You’d like to avoid
making the Bid persistent explicitly with an extra save() operation.
To enable this transitive state across the association, add a cascade option to the XML mapping:
<set name="bids" inverse="true" cascade="save-update">
<key column="ITEM_ID" />
<one-to-many class="Bid" />
</set>
• Note - deletion of an item implies deletion of all bids for the item. If you want to happen automatically then
Cascade = "save-update, delete"> otherwise we will be doing the following
Item anItem = // Load an item
// Delete all the referenced bids
for ( Iterator<Bid> it = anItem.getBids().iterator(); it.hasNext(); ) {
Bid bid = it.next();
it.remove(); // Remove reference from collection
session.delete(bid); // Delete it from the database
}
session.delete(anItem); // Finally, delete the item
• Enabling orphan deletion – we want to delete a Bid from the database. Note that you aren’t deleting the parent
(the Item) in this case. The goal is to remove a row in the BID table. Look at this code:
anItem.getBids().remove(aBid);
If the collection has the Bid mapped as a collection of components (value type), this code triggers several operations:
• The aBid instance is removed from the collection Item.bids.
• Because Bid is mapped as a value type, and no other object can hold a reference to the aBid
instance, the row representing this bid is deleted from the BID table by Hibernate.
In other words, Hibernate assumes that aBid is an orphan if it’s removed from its owning entity’s
collection. No other in-memory persistent object is holding a reference to it
However, what if Bid is mapped as an entity and the collection is a <one-to-many>?
The code changes to
anItem.getBids().remove(aBid);
session.delete(aBid);
The aBid instance has its own lifecycle, so it can exist outside of the collection. By deleting it manually, you guarantee
that nobody else will hold a reference to it, and the row can be removed safely. You may have removed all other
references manually. Or, if you didn’t, the database constraints prevent any inconsistency, and you see a foreign key
constraint exception.

Hibernate offers you a way to declare this guarantee for collections of entity references.
<set name="bids" inverse="true" cascade="save-update, delete, delete-orphan">

Note – we used <one-to-many> inside a <set> we have other options like <bag>, <list> even we can implement
this association with a join table.
Bags have the most efficient performance characteristics of all the collections you can use for a bidirectional one-to-many entity
association (in other words, if the collection side is inverse="true"). By default, collections in Hibernate are loaded only
when they’re accessed for the first time in the application. Because a bag doesn’t have to maintain the index of its elements (like
a list) or check for duplicate elements (like a set), you can add new elements to the bag without triggering the loading.

<class name="Bid" table="BID">


...
<many-to-one name="item" column="ITEM_ID" class="Item" not-null="true"/>
</class>
<class name="Item" table="ITEM">
...
<bag name="bids" inverse="true">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</bag>
</class>

24 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Many-to-many associations

A many-to-many valued association between Category and Item.

Unidirectional many-to-many association – category.hbm.xml


<set name="items" table="CATEGORY_ITEM" cascade="save-update">
<key column="CATEGORY_ID" />
<many-to-many class="Item" column="ITEM_ID" />
</set>
The join table has two columns: the foreign keys of the CATEGORY and ITEM tables. The primary key is a composite of both
columns.

you can also switch to an <idbag> with a separate primary key


column on the join table:
<idbag name="items" table="CATEGORY_ITEM”
cascade="save-update">
<collection-id type="long" column="CATEGORY_ITEM_ID">
<generator class="sequence"/>
</collection-id>
<key column="CATEGORY_ID"/>
<many-to-many class="Item" column="ITEM_ID"/>
</idbag>

Note - There are other options also like <list>,<map> etc.

Bidirectional many-to-many association

You know that one side in a bidirectional association has to be mapped as inverse because you have named the
foreign key column(s) twice. The same principle applies to bidirectional many-to-many associations

Recall this mapping of the items collection:


Category.hbm.xml
<set name="items" table="CATEGORY_ITEM" cascade="save-update">
<key column="CATEGORY_ID"/>
<many-to-many class="Item" column="ITEM_ID"/>
</set>
You may reuse this mapping for the Category end of the bidirectional association and map the other side as follows:
Item.hbm.xml
<set name="categories" table="CATEGORY_ITEM” inverse="true" cascade="save-update">
<key column="ITEM_ID"/>
<many-to-many class="Category" column="CATEGORY_ID"/>
</set>

25 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Hope you will be completely messed with one-to-one, one-to-many, many-to-one and many-to-many association
mappings. Let’s take some simple mappings-

Mapping class inheritance

Approach 1 - using <union-subclass>

<hibernate-mapping>
<class name="BillingDetails" abstract="true">  1
<id name="id" column="BILLING_DETAILS_ID" type="long">  2
<generator class="hilo" />
</id>
<property name="name" column="OWNER" type="string" />  3

<union-subclass name="CreditCard" table="CREDIT_CARD">  4


<property name="number" column="NUMBER" />
<property name="expMonth" column="EXP_MONTH" />
<property name="expYear" column="EXP_YEAR" />
</union-subclass>
<union-subclass name="BankAccount" table="BANK_ACCOUNT">
...
</class>
</hibernate-mapping>
1. An abstract superclass or an interface has to be declared as abstract="true"; otherwise a separate table for
instances of the superclass is needed.
2. The database identifier mapping is shared for all concrete classes in the hierarchy. The CREDIT_CARD
and the BANK_ACCOUNT tables both have a BILLING_DETAILS_ID primary key column. The
database identifier property now has to be shared for all subclasses; hence you have to put it into
BillingDetails and not in CreditCard and BankAccount.
3. Properties of the superclass (or interface) are declared here and inherited by all concrete class mappings.
This avoids duplication of the same mapping.
4. A concrete subclass is mapped to a table; the table inherits the superclass (or interface) identifier and
other property mappings.

26 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Approach 2 – Table per Hierarchy <subclass> with <discriminator>

This mapping strategy is a winner in terms of both performance


and simplicity. It’s the best-performing way to represent
polymorphism—both polymorphic and non polymorphic
queries perform well—and it’s even easy to implement by
hand.

Problems -
1. Columns for properties declared by subclasses must be declared
to be nullable. If your subclasses each define several non
nullable properties, the loss of NOT NULL constraints may be a
serious problem from the point of view of data integrity
2. Another important issue is normalization.

<class name="BillingDetails" table="BILLING_DETAILS"> 1


<id name="id" column="BILLING_DETAILS_ID" type="long">
<generator class="native" />
</id>
<discriminator column="BILLING_DETAILS_TYPE" type="string" /> 2
<property name="name" column="OWNER" type="string" /> 3
<subclass name="CreditCard" discriminator-value="CC"> 4
<property name="number" column="CC_NUMBER" />
<property name="expMonth" column="CC_EXP_MONTH" />
<property name="expYear" column="CC_EXP_YEAR" />
</subclass>
<subclass name="BankAccount" discriminator-value="BA">
<property name="bankName" column="BA_NUMBER" />
<property name="account" column="BA_ACCOUNT" />
</subclass>
</class>

1. The root class BillingDetails of the inheritance hierarchy is mapped to the table BILLING_DETAILS.
2. You have to add a special column to distinguish between persistent classes: the discriminator. This isn’t a
property of the persistent class; it’s used internally by Hibernate. The column name is
BILLING_DETAILS_TYPE, and the values are strings—in this case, “CC” or “BA”. Hibernate
automatically sets and retrieves the discriminator values.
3. Properties of the superclass are mapped as always, with a simple <property> element.
4. Every subclass has its own <subclass> element. Properties of a subclass are mapped to columns in the
BILLING_DETAILS table. Remember that NOT NULL constraints aren’t allowed, because a
BankAccount instance won’t have an expMonth property, and the CC_EXP_MONTH field must be
NULL for that row.

Note - The <subclass> element can in turn contain other nested <subclass> elements, until the whole
hierarchy is mapped to the table.

27 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

Hibernate generates the following SQL when querying the BillingDetails class:
select
BILLING_DETAILS_ID, BILLING_DETAILS_TYPE, OWNER, CC_NUMBER, CC_EXP_MONTH, ..., BA_ACCOUNT,
BA_BANKNAME, ...
from BILLING_DETAILS

To query the CreditCard subclass, Hibernate adds a restriction on the discriminator


column:
select
BILLING_DETAILS_ID, OWNER, CC_NUMBER, CC_EXP_MONTH, ...
from BILLING_DETAILS
where BILLING_DETAILS_TYPE='CC'

28 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Approach 3 - Table for everything <joined-subclass>

In this every class/subclass that declares persistent properties—including abstract classes and even interfaces—
has its own table. Unlike the table per concrete class strategy we mapped first, the table here contains columns
only for each non inherited property (each property declared by the subclass itself) along with a primary key that
is also a foreign key of the superclass table.
<class name="BillingDetails" table="BILLING_DETAILS"> 1
<id name="id" column="BILLING_DETAILS_ID" type="long">
<generator class="native" />
</id>

<joined-subclass name="CreditCard" table="CREDIT_CARD"> 2


<key column="CREDIT_CARD_ID" /> 3
<property name="number" column="NUMBER" />
<property name="expMonth" column="EXP_MONTH" />
<property name="expYear" column="EXP_YEAR" />
</joined-subclass>
<joined-subclass name="BankAccount" table="BANK_ACCOUNT">
<key column="BANK_ACCOUNT_ID" />
<property name="account" column="ACCOUNT_NO" />
<property name="bankName" column="BANK_NAME" />
</joined-subclass>
</class>

1. The root class BillingDetails is mapped to the table BILLING_DETAILS. Note that no discriminator is
required with this strategy.
2. The new <joined-subclass> element maps a subclass to a new table—in this example, CREDIT_CARD.
All properties declared in the joined subclass are mapped to this table.
3. A primary key is required for the CREDIT_CARD table. This column also has a foreign key constraint to
the primary key of the BILLING_DETAILS table. A Credit-Card object lookup requires a join of both
tables. A <joined-subclass> element may contain other nested <joined-subclass> elements, until the
whole hierarchy has been mapped.

29 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Choosing a strategy - By default, choose table-per-class-hierarchy only for simple problems. For more
complex cases (or when you’re overruled by a data modeler insisting on the importance of nullability constraints
and normalization), you should consider the table-per-subclass (table-for-everything) strategy.
Polymorphic many-to-one associations

User references one particular BillingDetails object, which at runtime can be any concrete instance of that class.
<many-to-one name="defaultBillingDetails" class="BillingDetails"
column="DEFAULT_BILLING_DETAILS_ID"/>

But because BillingDetails is abstract, the association must refer to an instance of one of its subclasses—CreditCard or
BankAccount—at runtime.

You don’t have to do anything special to enable polymorphic associations in Hibernate. Hibernate is intelligent to identify the
concrete implementation.
CreditCard cc = new CreditCard();
cc.setNumber(ccNumber);
cc.setType(ccType);
cc.setExpiryDate(ccExpiryDate);

User user = (User) session.get(User.class, userId);


user.addBillingDetails(cc); // Add it to the one-to-many association
user.setDefaultBillingDetails(cc);
// Complete unit of work

Now, when you navigate the association in a second unit of work, Hibernate automatically retrieves the
CreditCard instance:
User user = (User) secondSession.get(User.class, userId);
// Invoke the pay() method on the actual subclass instance
user.getDefaultBillingDetails().pay(amount);
A User may have references to many BillingDetails, not only a single default (one of the many is the default). You map this with a
bidirectional one-to-many association. In BillingDetails, you have the following:
<many-to-one name="user" class="User" column="USER_ID"/>
In the Users mapping you have:
<set name="billingDetails" inverse="true">
<key column="USER_ID"/>
<one-to-many class="BillingDetails"/>
</set>
Adding a CreditCard is easy:
CreditCard cc = new CreditCard();
cc.setNumber(ccNumber);
cc.setType(ccType);
User user = (User) session.get(User.class, userId);
// Call convenience method that sets both sides of the association
user.addBillingDetails(cc);
// Complete unit of work

30 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Exercise - Online Bidding Application

One-to-one (can be mapped as many-to-one with unique constraints)


Making a association uni or bi directional completely depends on the application need. So always ask question
like is it really required to fetch User object from Address object? Or if we have User object then only move to
address object, it makes more sense.
1. User can have at most one home, shipping and billing address.
2. User can have at most one default billing detail out of several billing type options.
3. Shipment can be done at only one delivery address.
4. One Item can have only one successful bid out of many bids placed.
5. One comment can be post for per item per user.
6. One item can be shipped once, obliviously.
7. In shipment there will be one buyer and one seller.
8. Each Bid will belong to one user for a specific item.
9. One Item will be placed by one specific User.
One-to-many and many-to-one (if you want to make one-to-many bidirectional)
1. One User can have multiple billing options.
2. One user can buy, sell many items.
3. One item can have many bids.
4. One category can have multiple child categories and many child categories will belong to one parent
category.

31 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Many-to-many
One category can have many items and one item can belong to multiple categories. Like one mouse can belong to
electronics, computers accessories categories.
After Few Modifications, We could generate the following UML Class Diagram-

-billingAddress, -homeAddress, -deliveryAddress, -shippingAddress, -buyer, -seller etc are the relationship
names. Multiplicity is not shown but above we have already discussed one-to-many etc association among these
classes.

32 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
User and Address (value type)

-homeAddress
<component name="homeAddress" class="Address">
<property name="street" type="string" column="HOME_STREET" length="255" />
<property name="zipcode" type="string" column="HOME_ZIPCODE" length="16" />
<property name="city" type="string" column="HOME_CITY" length="255" />
</component>

-billingAddress
<join table="BILLING_ADDRESS" optional="true">
<key column="USER_ID" foreign-key="FK_BILLING_ADDRESS" />
<component name="billingAddress" class="Address">
<property name="street" type="string" column="STREET" length="255" />
<property name="zipcode" type="string" column="ZIPCODE" length="16" />
<property name="city" type="string" column="CITY" length="255" />
</component>
</join>

User and AddressEntity (entity type)


-shippingAddress
<!-- A one-to-one shared primary key entity association -->
<one-to-one name="shippingAddress" class="AddressEntity" cascade="save-update" />

For making this association bidirectional put this mapping in AddressEntity


<one-to-one name="user" class="User" constrained="true" foreign-key="FK_ADDRESS_USERS_SHARED_PK"/>

Shipment and AddressEntity


-deliveryAddress
<! -- The instance referenced here can be shared, as the shippingAddress of a User -->
<many-to-one name="deliveryAddress" class="AddressEntity" column="DELIVERY_ADDRESS_ID"
not-null="true" update="false" fetch="join" foreign-key="FK_DELIVERY_ADDRESS_ID"/>

Item and User


-approvedBy
<!-- Who approved this auction -->
<many-to-one name="approvedBy" class="User" column="APPROVED_BY_USER_ID"
not-null="false" foreign-key="FK_APPROVED_BY_USER_ID"/>
-seller
<!-- Immutable property, bi-directional with bag on the other side -->
<many-to-one name="seller" class="User" column="SELLER_ID" update="false"
not-null="true" foreign-key="FK_SELLER_ID"/>

-buyer
<!-- The bidirectional association for the optional buyer-->
<join table="ITEM_BUYER" optional="true" inverse="true" fetch="select">
<key column="ITEM_ID"/>
<many-to-one name="buyer" class="User" column="USER_ID"/>
</join>

User side-
-itemForSale (Not Shown in class dig.)
<bag name="itemsForSale" inverse="true">
<key column="SELLER_ID" />
<one-to-many class="Item" />
</bag>

33 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
-boughtItems
<!-Mapping for the optional 1-to-many association to bought items, across a join table -->
<set name="boughtItems" table="ITEM_BUYER">
<key column="USER_ID" foreign-key="FK_ITEM_BUYER_USER_ID" />
<many-to-many class="Item" column="ITEM_ID" unique="true"
foreign-key="FK_ITEM_BUYER_ITEM_ID" />
</set>
Note -It is quite similar to when we map 1-to-1 with many-to-1 mapping with unique=”true”

User and Bid


-bids (All bids placed by a USER)
<set name="bids" cascade="save-update" inverse="true">
<key column="USER_ID" not-null="true" />
<one-to-many class="Bid" />
</set>
-bidder
<! -- The other side of this bidirectional one-to-many association to user ->
<many-to-one name="bidder" class="User" column="BIDDER_ID" update="false"
not-null="true" foreign-key="FK_BIDDER_ID"/>

Item and Bid

-successfulBid
<!-- Successful bid with property-ref trick.-->
<one-to-one name="successfulBid" lazy="no-proxy" property-ref="successReference"/>

-item
<!-- Grouped inside a <properties> element for reference in legacy schema... -->
<properties name="successReference">
<property name="successful" column="IS_SUCCESSFUL" type="boolean"
not-null="true"/>

<!-- Read-only "inverse" side of the indexed one-to-many collection in Item -->
<many-to-one name="item" class="Item" column="ITEM_ID"
not-null="true" insert="false" update="false" foreign-key="FK_ITEM_ID"/>
</properties>

Shipment and User

-buyer
<many-to-one name="buyer" class="User" column="BUYER_ID" not-null="true"
update="false" fetch="join" foreign-key="FK_SHIPMENT_BUYER_ID"/>
-seller
<many-to-one name="seller" class="User" column="SELLER_ID" not-null="true"
update="false" fetch="join" foreign-key="FK_SHIPMENT_SELLER_ID"/>

Shipment and Item

-auction
<!-- The optional link to a particular auction, via a link table, the unqiue="true" on the
ITEM_ID makes this a one-to-zero-or-one association. -->

<join table="ITEM_SHIPMENT" optional="true">


<key column="SHIPMENT_ID" foreign-key="FK_ITEM_SHIPMENT_SHIPMENT_ID"/>
<many-to-one name="auction" column="ITEM_ID" not-null="true"
unique="true" foreign-key="FK_ITEM_SHIPMENT_ITEM_ID"/>
</join>

34 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
User and BillingDetails

-billingDetails
<!-- Regular inverse one-to-many association with a set -->
<set name="billingDetails" cascade="save-update" inverse="true">
<key column="USER_ID" not-null="true" />
<one-to-many class="BillingDetails" />
</set>

-user
<!-- The non-inverse side of the one-to-many/many-to-one between User and BillingDetails
class -->
<many-to-one name="user" class="User" column="USER_ID" update="false"
foreign-key="FK_USER_ID"/>

BillingDetails with BankAccount and CreditCard (sub classes)


<!-- CreditCard subclass mapping to its own table, normalized.
CreditCard is immutable, we map all properties with update="false" -->
<subclass name="CreditCard" discriminator-value="CC">
<join table="CREDIT_CARD" fetch="select">
<key column="CREDIT_CARD_ID" foreign-key="FK_CREDIT_CARD_SUPERCLASS"/>
<property name="type" type="credit_card_type" column="CC_TYPE"
update="false" not-null="true"/>
<property name="number" type="string" column="CC_NUMBER"
length="16" update="false" not-null="true"/>
<property name="expMonth" type="string" column="CC_EXP_MONTH"
length="2" update="false" not-null="true"/>
<property name="expYear" type="string" column="CC_EXP_YEAR"
length="4" update="false" not-null="true"/>
</join>
</subclass>

<!-- BankAccount goes into the hierarchy table, columns have to be nullable -->
<subclass name="BankAccount" discriminator-value="BA">
<property name="account" type="string" column="BA_ACCOUNT"
length="16" not-null="false"/>
<property name="bankname" type="string" column="BA_BANKNAME"
length="255" not-null="false"/>
<property name="swift" type="string" column="BA_SWIFT" length="15"
not-null="false"/>
</subclass>

Category and Item

-parentCategory
<many-to-one name="parentCategory" class="Category" foreign-key="FK_CATEGORY_PARENT_ID">
<column name="PARENT_CATEGORY_ID" not-null="false"/>
</many-to-one>

- childCategories
<!-- The inverse side of the one-to-many/many-to-one association, we use a bag mapping,
iteration order of this collection is by category name. -->
<bag name="childCategories" cascade="save-update, merge" nverse="true"
order-by="CATEGORY_NAME asc">
<key column="PARENT_CATEGORY_ID"/>
<one-to-many class="Category"/>
</bag>

35 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
-items
<!-- The pure many-to-many association to Item, a true persistent list with index -->
<list name="items" table="CATEGORY_ITEM">
<key column="CATEGORY_ID" foreign-key="FK_CATEGORY_ITEM_CATEGORY_ID"/>
<list-index column="DISPLAY_POSITION"/>
<many-to-many class="Item" column="ITEM_ID" foreign-key="FK_CATEGORY_ITEM_ITEM_ID"/>
</list>

Category Side
<!-- This is an alternative for the many-to-many association to Item. We use a one-to-many
association to express the relationship to a set of items. There is an intermediate entity
class, CategorizedItem, which effectively makes this a many-to-many association between
Category and Item. You can use this mapping style if your association table has
additional columns. These are then properties of the CategorizedItem entity class.
To create a link, instantiate a CategorizedItem with the right constructor. To remove a
link, use getCategorizedItems().remove() on this class (mapped with orphan delete). -->

<set name="categorizedItems" cascade="all,delete-orphan" inverse="true" fetch="subselect">


<key column="CATEGORY_ID" not-null="true"/>
<one-to-many class="CategorizedItem"/>
</set>

Item side
<!-- We use a one-to-many association to express the relationship to a set of categories.
There is an intermediate entity class, CategorizedItem, which effectively makes this a
many-to-many association between Item and Category. -->
<set name="categorizedItems" cascade="all, delete-orphan" inverse="true">
<key column="ITEM_ID" not-null="true"/>
<one-to-many class="CategorizedItem"/>
</set>

CategoraziedItem Side
<!-- Read-only association property -->
<many-to-one name="item" column="ITEM_ID" not-null="true"
insert="false" update="false" foreign-key="FK_CATEGORIZED_ITEM_ITEM_ID"/>

<!-- Read-only association property -->


<many-to-one name="category" column="CATEGORY_ID" not-null="true"
insert="false" update="false" foreign-key="FK_CATEGORIZED_ITEM_CATEGORY_ID"/>

For mastering association mapping one required lots of practice. I will say understand
above application and different ways of mapping completely and refer this whenever you are
modeling a new application.

For covering most of the mapping types the above examples may looks difficult. What you
can do first restrict to uni-directional mappings and use simpler ways of association then
take steps towards bi-directional mapping and other options.

Now, we will discuss optimization Techniques (minimizing database hit) used by Hibernate.

Yes it is most wanted concept of lazy=”true/false” (Hibernate Proxy) instances. Other most wanted
concepts are
1. inverse=”true”  Already discussed
2. property-ref  Already discussed
3. <bag>, <set>, <list>, <component>  Already Discussed
4. ways of mapping an association <one-to-many> etc.  Already discussed
5. Optimization - lazy loading (using Proxies), join, subselect, second level caching, optimistic locking etc. ;->

36 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Optimization - Lazy Loading (Hibernate Proxy instance(s)) –

Step 1 – First, understand Persistence Lifecycle

Transient Object
Item item = new Item();
Objects instantiated using the new operator aren’t immediately persistent. Their state is transient, which means
they aren’t associated with any database table row and so their state is lost as soon as they’re no longer
referenced by any other object. These objects have a lifespan that effectively ends at that time, and they become
inaccessible and available for garbage collection.

Persistent Object
A persistent instance is an entity instance with a database identity.
1. May be objects instantiated by the application and then made persistent by calling one of the methods on the
persistence manager.
2. May even be objects that became persistent when a reference was created from another persistent object that is
already managed.
3. May be an instance retrieved from the database by execution of a query, by an identifier lookup, or by
navigating the object graph starting from another persistent instance.

Detached Object
First understand what mean by “unit of work“
Beginning a unit of work
At the beginning of a unit of work, an application obtains an instance of Session from the application’s SF,
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
At this point, a new persistence context is also initialized for you, and it will manage all the objects you work
with in that Session.
All operations you execute inside a unit of work occur inside a transaction, no matter if you read or write data.

37 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Item item = new Item();  Transient Object, you may also instantiate it after opening a Session;
item.setName("laptop with all accessories");
item.setEndDate( ... );

Session session = sessionFactory.openSession();


Transaction tx = session.beginTransaction();

Serializable itemId = session.save(item);  Persistent Object, It’s now associated with the current
Session and its persistence context.
tx.commit();  flush() happens here, you may flush() manually
session.close();  persistence context ends here

 From here onwards item is a detached object 


.. … … …
… …. …

Removed Object
An object is in the removed state if it has been scheduled for deletion at the end of a unit of work, but it’s still
managed by the persistence context until the unit of work completes. In other words, a removed object shouldn’t
be reused because it will be deleted from the database as soon as the unit of work completes. You should also
discard any references you may hold to it in the application.

Step 2 – Understanding proxies


Item item = (Item) session.load(Item.class, new Long(123));

General Thinking –
This retrieval by identifier results in a single (or possibly several, if inheritance or secondary tables are mapped) SQL statement
that retrieves an Item instance. In the persistence context, in memory, you now have this item object available in persistent
state

Actual Happening –
What is available in memory after the load() operation isn’t a persistent item object. Even the SQL that loads an
Item isn’t executed. Hibernate created a proxy that looks like the real thing.

38 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Proxies are placeholders that are generated at runtime. Whenever Hibernate returns an instance of an entity class,
it checks whether it can return a proxy instead and avoid a database hit. A proxy is a placeholder that triggers
the loading of the real object when it’s accessed for the first time:

Item item = (Item) session.load(Item.class, new Long(123));


item.getId();
item.getDescription(); // Initialize the proxy

The third line in this example triggers the execution of the SQL that retrieves an Item into memory. As long as
you access only the database identifier property, no initialization of the proxy is necessary.

A proxy is useful if you need the Item only to create a reference, for example:

Item item = (Item) session.load(Item.class, new Long(123));


User user = (User) session.load(User.class, new Long(1234));
Bid newBid = new Bid("99.99");
newBid.setItem(item);
newBid.setBidder(user);
session.save(newBid);

You first load two objects, an Item and a User. Hibernate doesn’t hit the database to do this: It returns two
proxies. This is all you need, because you only require the Item and User to create a new Bid. The save(newBid)
call executes an INSERT statement to save the row in the BID table with the foreign key value of an Item and a
User—this is all the proxies can and have to provide. The previous code snippet doesn’t execute any SELECT!

get() vs. load()


If you call get() instead of load() you trigger a database hit and no proxy is returned. The get() operation always
hits the database (if the instance isn’t already in the persistence context and if no transparent second-level cache
is active) and returns null if the object can’t be found.

The load() method throws an ObjectNotFound-Exception. You may also get an ObjectNotFoundException later,
as soon as you try to access the returned placeholder and force its initialization.

Let’s assume you have an Item instance into memory, either by getting it explicitly or by calling one of its
properties and forcing initialization of a proxy. Your persistence context now contains a fully loaded object, as
shown in figure below.

Again, you can see proxies in the picture. This time, these are proxies that have been generated for all *-to-one
associations. Associated entity objects are not loaded right away; the proxies carry the identifier values only.
From a different perspective: the identifier values are all foreign key columns in the item’s row.

39 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Collections also aren’t loaded right away, but we use the term collection wrapper to describe this kind of
placeholder. Internally, Hibernate has a set of smart collections that can initialize themselves on demand.
Hibernate replaces your collections with these; that is why you should use collection interfaces only in your
domain model. By default, Hibernate creates placeholders for all associations and collections, and only retrieves
value-typed properties and components right away.

A proxy is initialized if you call any method that is not the identifier getter method, a collection is initialized if
you start iterating through its elements or if you call any of the collection-management operations, such as size()
and contains().

Disabling Lazy
You can disable proxy generation for a particular entity class with the lazy="false" attribute in XML mapping
metadata:
<class name="User" table="USERS" lazy="false">
...
</class>

LazyInitializationException
If a proxy instance or collection wasn’t initialized before the persistence context was closed and you tried to
access them after closing the unit of work (detached state), you will face this exception.

Prefetching data in batches


<class name="User" table="USERS" batch-size="10">
...
</class>

You’re telling Hibernate to prefetch up to 10 uninitialized proxies in a single SQL SELECT, if one proxy must
be initialized.

Batch fetching is also available for collections:


<class name="Item" table="ITEM">
...
<set name="bids" inverse="true" batch-size="10">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
</class>
If you now force the initialization of one bids collection, up to 10 more collections of the same type, if they’re
uninitialized in the current persistence context, are loaded right away:

select items...
select b.* from BID b where b.ITEM_ID in (?, ?, ?)

In this case, you again have three Item objects in persistent state, and touching one of the unloaded bids
Collections. Now all three Item objects have their bids loaded in a single SELECT.

40 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Prefetching collections with subselects

In Batch fetching you’d need to figure out an optimum batch size by trial. A much better optimization is
subselect fetching for this collection mapping:
<class name="Item" table="ITEM">
...
<set name="bids" inverse="true" fetch="subselect">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
</class>
Hibernate now initializes all bids collections for all loaded Item objects, as soon as you force the initialization of
one bids collection. It does that by rerunning the first initial query (slightly modified) in subselect:

select i.* from ITEM I


select b.* from BID b where b.ITEM_ID in (select i.ITEM_ID from ITEM i)

Eager fetching with joins


Lazy loading is an excellent default strategy. On other hand, you can often look at your domain and data model
and say, “Every time I need an Item, I also need the seller of that Item.” If you can make that statement, you
should go into your mapping metadata, enable eager fetching for the seller association, and utilize SQL joins:
<class name="Item" table="ITEM">
...
<many-to-one name="seller" class="User" column="SELLER_ID" update="false" fetch="join"/>
</class>
Hibernate now loads both an Item and its seller in a single SQL statement. For example:

Item item = (Item) session.get(Item.class, new Long(123));

This operation triggers the following SQL SELECT:


select i.*, u.* from ITEM I left outer join USERS u on i.SELLER_ID = u.USER_ID where i.ITEM_ID = ?
Obviously, the seller is no longer lazily loaded on demand, but immediately. Hence, a fetch="join" disables lazy
loading.

Forcing proxy and collection initialization


You sometimes want to work with a network of objects in detached state. You retrieve all objects and collections
that should be detached and then close the persistence context.
In this scenario, it’s sometimes useful to explicitly initialize an object before closing the persistence context,
without resorting to a change in the global fetching strategy or a different query (which we consider the solution
you should always prefer). You can use the static method Hibernate.initialize() for manual initialization of a
proxy:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
Hibernate.initialize( item.getSeller() );
tx.commit();
session.close();
processDetached( item.getSeller() );
Hibernate.initialize() may be passed a collection wrapper or a proxy

41 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

Optimization - Hibernate Caching


A cache keeps a representation of current database state close to the application, either in memory or on disk of
the application server machine. The cache is a local copy of the data. The cache sits between your application
and the database. The cache may be used to avoid a database hit whenever
• The application performs a lookup by identifier (primary key).
• The persistence layer resolves an association or collection lazily.
It’s also possible to cache the results of queries, but less useful.

Hibernate has a two-level cache architecture,


• The first-level cache is the persistence context cache. A Hibernate Session lifespan corresponds to
either a single request (usually implemented with one database transaction) or a conversation. This is a
mandatory first-level cache that also guarantees the scope of object and database identity
• The second-level cache in Hibernate is pluggable. This is a cache of state (returned by value), not of
actual persistent instances. Use of the second-level cache is optional and can be configured on a per-class
and per-collection basis—each such cache utilizes its own physical cache region.

Cache providers - EHCache, OpenSymphony’s OSCache, SwarmCache, JBoss Cache etc. Each provider
provides its own set of functionalities. We can configure those by customizing vendor specific properties.

We have disabled second level cache in our hibernate.cfg.xml


<!-- Disable the second-level cache -->
<property name="cache.provider_class">
org.hibernate.cache.NoCacheProvider
</property>

42 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

Optimization – Optimistic concurrency control


A transaction may place a lock on a particular item of data in the database, temporarily preventing access to that
item by other transactions. Several isolation levels are available, which, naturally, weaken full isolation but
increase performance and scalability of the system.

Transaction isolation issues

A lost update occurs if two transactions both update a row


and then the second transaction aborts, causing both changes
to be lost. This occurs in systems that don’t implement
locking. The concurrent transactions aren’t isolated.

A dirty read occurs if a one transaction reads changes made by


another transaction that has not yet been committed. This is
dangerous, because the changes made by the other transaction
may later be rolled back, and invalid data may be written by the
first transaction.

An unrepeatable read occurs if a transaction reads a row


twice and reads different state each time. For example, another
transaction may have written to the row and committed
between the two reads. A special case of unrepeatable read is
the second lost updates problem. Imagine that two concurrent
transactions both read a row: One writes to it and commits, and
then the second writes to it and commits. The changes made by
the first writer are lost

A phantom read is said to occur when a transaction executes


a query twice, and the second result set includes rows that
weren’t visible in the first result set or rows that have been
deleted. This situation is caused by another transaction
inserting or deleting rows between the executions of the two
queries.

43 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

Hibernate sets this isolation level on every JDBC connection obtained from a connection pool before starting a
transaction.

• 1—Read uncommitted isolation - A system that permits dirty reads but not lost updates. One transaction
may not write to a row if another uncommitted transaction has already written to it. Any transaction may
read any row, however. This isolation level may be implemented in the database-management system
with exclusive write locks.

• 2—Read committed isolation - A system that permits unrepeatable reads but not dirty reads. This may
be achieved by using shared read locks and exclusive write locks. Reading transactions don’t block other
transactions from accessing a row. However, an uncommitted writing transaction blocks all other
transactions from accessing the row.

• 4—Repeatable read isolation - A system that permits neither unrepeatable reads nor dirty reads.
Phantom reads may occur. Reading transactions block writing transactions (but not other reading
transactions), and writing transactions block all other transactions.

• 8—Serializable isolation - provides the strictest transaction isolation. This isolation level emulates serial
transaction execution, as if transactions were executed one after another, serially, rather than
concurrently.

You may also set the transaction isolation for JDBC connections on the application side, with a Hibernate
configuration option:
hibernate.connection.isolation = 4

Note that Hibernate never changes the isolation level of connections obtained from an application server-
provided database connection in a managed environment! You can change the default isolation using the
configuration of your application server.

Too great a degree of isolation harms scalability of a highly concurrent application. Insufficient isolation may
cause subtle,
unreproduceable bugs in an application that you’ll never discover until the system is working under heavy load.

Generally we choose isolation level either read committed or repeatable read.

Let’s take Repeatable Read. This isolation level eliminates the possibility that one transaction can overwrite
changes made by another concurrent transaction (the second lost updates problem) if all data access is performed
in a single atomic database transaction. A read lock held by a transaction prevents any write lock a concurrent
transaction may wish to obtain. This is an important issue, but enabling repeatable read isn’t the only way to
resolve it.

44 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Optimistic Concurrency Control

Imagine that two transactions read a particular object from the database, and both modify it. Thanks to the read-
committed isolation level of the database connection, neither transaction will run into any dirty reads. However,
reads are still nonrepeatable, and updates may also be lost. This is a problem you’ll face when you think about
conversations, which are atomic transactions from the point of view of your users.

The changes made in conversation A have been lost, and (potentially worse) modifications of data committed in
conversation B may have been based on stale information.
You have three choices for how to deal with lost updates in these second transactions in the conversations:
• Last commit wins
• First commit wins—the transaction of conversation A is committed, and the user committing the
transaction in conversation B gets an error message. The user must restart the conversation by retrieving
fresh data and go through all steps of the conversation again with non stale data. (Seems more logical)
• Merge conflicting updates

What if we want to set isolation level “Read_Committed” and also do not want lost update chances as in above
case? Here is the concept of data versioning come into picture.

Suppose if each entity instance has a version, which can be a number or a timestamp and Hibernate will
increments an object’s version when it’s modified, compares versions automatically, and throws an exception if a
conflict is detected. Yes, hibernate has this automatic feature but you have to enable this.

Enabling versioning in Hibernate


Step 1 – add this version property to all your persistent entity classes to enable optimistic locking:
public class Item {
...
private int version;
...
}
Step 2 - The <version> property mapping in XML must be placed immediately after the identifier property
<class name="Item" table="ITEM">
<id .../>
<version name="version" access="field" column="OBJ_VERSION"/>
...
</class>

45 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!
Note – Sometimes a timestamp is preferred (or exists):
public class Item {
...
private Date lastUpdated;
...
}
<class name="Item" table="ITEM">
<id .../>
<timestamp name="lastUpdated" access="field" column="LAST_UPDATED"/>
...
</class>
In theory, a timestamp is slightly less safe, because two concurrent transactions may both load and update the
same item in the same millisecond; in practice, this won’t occur because a JVM usually doesn’t have millisecond
accuracy

So now you know what “StaleObjectStateException” is ;-)

Note - If you want to disable automatic increment for a particular value-typed property or collection, map it with
the optimistic-lock="false" attribute.

The combination of the (mandatory) persistence context cache and versioning already gives you most of the nice
features of repeatable read isolation. In particular, versioning prevents the second lost updates problem, and the
persistence context cache also ensures that the state of the persistent instances loaded by one transaction is
isolated from changes made by other transactions. So, read-committed isolation for all database transactions is
acceptable if you use versioned data.

Obtaining additional isolation guarantees


What if you need better isolation guarantees only for a particular unit of work? Hibernate provides a way to set it
runtime
Item i = (Item) session.get(Item.class, 123);  1ST READ

session.lock(i, LockMode.UPGRADE);

String description = (String)session.createQuery("select i.description from Item i" +


" where i.id = :itemid").setParameter("itemid", i.getId() ).uniqueResult();  2ND READ

Using LockMode.UPGRADE results in a pessimistic lock held on the database for the row(s) that represent the
Item instance. Now no concurrent transaction can obtain a lock on the same data—that is, no concurrent
transaction can modify the data between your two reads.

Shortcut - Item i = (Item) session.get(Item.class, 123, LockMode.UPGRADE);

Generally the common values are-


• LockMode.NONE—Don’t go to the database unless the object isn’t in any cache.(default for get and
load())
• LockMode.READ—Bypass all caches, and perform a version check to verify that the object in memory is
the same version that currently exists in the database.
• LockMode.UPDGRADE—Bypass all caches, do a version check (if applicable), and obtain a database-
level pessimistic upgrade lock, if that is supported.

46 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E
Asking is Good, so keep it up!!!

Querying the Database


There are three ways to express queries in Hibernate

Hibernate Query Language (HQL),


session.createQuery("from Category c where c.name like 'Laptop%'");

Criteria API for query by criteria (QBC) and query by example (QBE):
session.createCriteria(Category.class).add( Restrictions.like("name", "Laptop%") );

Direct SQL with or without automatic mapping of resultsets to objects:


session.createSQLQuery("select {c.*} from CATEGORY {c} where NAME like
'Laptop%'").addEntity("c", Category.class);

The org.hibernate.Query and org.hibernate.Criteria interfaces both define several methods for controlling
execution of a query.

To create a new Hibernate Query instance, call either createQuery() or create-SQLQuery() on a Session. The

createQuery() method prepares an HQL query:


Query hqlQuery = session.createQuery("from User");

createSQLQuery() is used to create an SQL query using the native syntax of the underlying database:
Query sqlQry = session.createSQLQuery( "select {user.*} from USERS {user}").addEntity("user", User.class);

In both cases, Hibernate returns a newly instantiated Query object.

To obtain a Criteria instance, call createCriteria(), passing the class of the objects you want the query to return.
This is also called the root entity of the criteria query, the User in this example:
Criteria crit = session.createCriteria(User.class);
The Criteria instance may be used in the same way as a Query object—but it’s also used to construct the object-
oriented representation of the query, by adding Criterion instances and navigating associations to new Criterias.

To create a native SQL query, use createNativeQuery():


Query sqlQuery = session.createNativeQuery( "select u.USER_ID, u.FIRSTNAME, u.LASTNAME from
USERS u",User.class);

The way you define the returned objects from a native query is slightly different than in Hibernate (there are no
placeholders in the query here).

Using named queries


Hibernate lets you externalize query strings to the mapping metadata, a technique that is called named queries.

In mapping file –
<query name="findItemsByDescription"><![CDATA[from Item item where item.description like :desc]]>
</query>
In Code -
session.getNamedQuery("findItemsByDescription").setString("desc", description);

47 | S u m i t A g r a w a l | T e c h n i c a l A r c h i t e c t | M C C R e t a i l C O E

You might also like