Step 7 - Hibernate
Step 7 - Hibernate
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.
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.
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
import java.util.Collection;
import javax.sql.RowSet;
• 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.
package org.test.model.oracle;
OracleDAOFactory
implements
implements
MySQLCustomerDAO MySQLOrderDAO MySQEmployeeDAO MySQDepartmentDAO
MySQLDAOFactory
/*****************DAOFactory**********************/
package org.test.model;
import org.test.model.mysql.MySQLDAOFactory;
import org.test.model.oracle.OracleDAOFactory;
switch (whichFactory) {
case MYSQL:
return new MySQLDAOFactory();
case ORACLE:
return new OracleDAOFactory();
// ...
default:
return null;
}
}
}
/*****************OracleDAOFactory**********************/
package org.test.model.oracle;
@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();
}
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.
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.
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
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;
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>
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-
How we can take out complete list of Person persisted into database-
List result = session.createQuery("from org.test.Person").list();
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
■ 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"
</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!!!
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.
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.
//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).
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.
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.
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.
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.
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();
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).
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
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.
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
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
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-
<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
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>
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.
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
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>
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);
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
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>
-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”
-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>
-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"/>
-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. -->
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"/>
<!-- 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>
-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). -->
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"/>
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)) –
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( ... );
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
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.
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:
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:
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!
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.
You’re telling Hibernate to prefetch up to 10 uninitialized proxies in a single SQL SELECT, if one proxy must
be initialized.
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:
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!!!
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.
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!!!
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.
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.
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
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.
session.lock(i, LockMode.UPGRADE);
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.
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!!!
Criteria API for query by criteria (QBC) and query by example (QBE):
session.createCriteria(Category.class).add( Restrictions.like("name", "Laptop%") );
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
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);
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.
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).
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