Hibernate Basics
Hibernate Basics
Hibernate Basics:
Hibernate is an open source Java persistence framework project. It performs powerful object-
relational mapping and query databases using HQL and SQL. Hibernate is a great tool for ORM
mappings in Java. It can cut down a lot of complexity and thus defects as well from your
application, which may otherwise find a way to exist. This is specially boon for developers with
limited knowledge of SQL.
The following diagram summarizes the main building blocks in hibernate architecture.
I want the id attribute should be generated automatically so that application code does
not store a local cache of employee ids.
So far we targeted what we want to make in our first application. Lets identify the files
need to be created.
1. hibernate.cfg.xml -This configuration file will be used to store database
connection information and schema level settings.
2. EmployeeEntity.java – This class will refer Java POJOs having hibernate
annotations.
3. HibernateUtil.java – This class will have utility methods which will be used for
creating session factory and session objects.
4. TestHibernate.java – This class will be used to test our configuration settings and
Emplyee entity annotations.
Requirement for pom.xml file, For now we will be using only few of them:
➔ pom.xml
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-commons-annotations</artifactid>
<version>3.0.0.ga</version>
</dependency>
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-annotations</artifactid>
<version>3.3.0.ga</version>
</dependency>
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<version>5.1.6</version>
</dependency>
<dependency>
<groupid>antlr</groupid>
<artifactid>antlr</artifactid>
<version>2.7.6</version>
</dependency>
<dependency>
<groupid>commons-collections</groupid>
<artifactid>commons-collections</artifactid>
<version>3.1</version>
</dependency>
<dependency>
<groupid>dom4j</groupid>
<artifactid>dom4j</artifactid>
<version>1.6.1</version>
</dependency>
<dependency>
<groupid>javassist</groupid>
<artifactid>javassist</artifactid>
<version>3.4.GA</version>
</dependency>
<dependency>
<groupid>javax.transaction</groupid>
<artifactid>jta</artifactid>
<version>1.1</version>
</dependency>
<dependency>
<groupid>org.slf4j</groupid>
<artifactid>slf4j-api</artifactid>
<version>1.5.6</version>
</dependency>
<dependency>
<groupid>org.slf4j</groupid>
<artifactid>slf4j-log4j12</artifactid>
<version>1.5.6</version>
</dependency>
➔ 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>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatetest
<property name="hibernate.connection.password">******</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping class="hibernate.test.dto.EmployeeEntity"></mapping>
</session-factory>
</hibernate-configuration>
hbm2ddl.auto ->
hibernate.hbm2ddl.auto Automatically validates or exports schema DDL to the database when the
SessionFactory is created. With create-drop, the database schema will be dropped when the
SessionFactory is closed explicitly.
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.OptimisticLockType;
@Entity
@org.hibernate.annotations.Entity(optimisticLock = OptimisticLockType.ALL)
@Table(name = "Employee", uniqueConstraints = {
@UniqueConstraint(columnNames = "ID"),
@UniqueConstraint(columnNames = "EMAIL") })
public class EmployeeEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
private Integer employeeId;
import java.io.File;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateUtil
{
private static final SessionFactory sessionFactory = buildSessionFactory();
➔ TestHibernate.java
package hibernate.test;
import hibernate.test.dto.EmployeeEntity;
import org.hibernate.Session;
session.getTransaction().commit();
HibernateUtil.shutdown();
}
}
Above code will create a new table employee in database and insert one row in this table.
In logs you can verify the insert statement which got executed.
➔ Console
Hibernate: insert into Employee (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Let’s look at different flavors of load() method available in hibernate session interface.
public class TestHibernate
{
public static void main(String[] args)
{
Session sessionOne = HibernateUtil.getSessionFactory().openSession();
sessionOne.beginTransaction();
//Save employee
sessionOne.save(emp);
//store the employee id generated for future use
Integer empId = emp.getEmployeeId();
sessionOne.getTransaction().commit();
/************************************************************************/
sessionTwo.getTransaction().commit();
}
}
The difference between get and load methods lies in return value when the identifier
does not exist in database.
➔ In case of get() method, we will get return value as NULL if identifier is absent.
But in case of load() method, we will get a runtime exception.
➔ Get method never returns a proxy, it either returns null or fully initialized Object,
while load() method may return proxy, which is the object with ID but without
initializing other properties, which is lazily initialized. If you are just using returned
object for creating relationship and only need Id then load() is the way to go.
In the same example as above, we will use below class to insert data in DB:
//Save employee
sessionOne.save(emp);
sessionOne.getTransaction().commit();
HibernateUtil.shutdown();
}
}
➔ Below will give error, because other session is used for save:
emp.setLastName("temp");
//Save employee again second time
sessionTwo.save(emp);
sessionTwo.getTransaction().commit();
HibernateUtil.shutdown();
}
}
//Save employee
sessionOne.save(emp);
emp.setLastName("temp");
//Save employee again second time
sessionOne.save(emp);
sessionOne.getTransaction().commit();
HibernateUtil.shutdown();
}
}
➔ SaveOrUpdate
public class SaveOrUpdateMethodExample
{
public static void main(String[] args)
{
Session sessionOne = HibernateUtil.getSessionFactory().openSession();
sessionOne.beginTransaction();
//Create new Employee object
EmployeeEntity emp = new EmployeeEntity();
emp.setEmployeeId(1);
emp.setFirstName("Rohit");
emp.setLastName("Patil");
//Save employee
sessionOne.save(emp);
sessionOne.getTransaction().commit();
emp.setLastName("temp");
//Save employee again second time
sessionTwo.saveOrUpdate(emp);
sessionTwo.getTransaction().commit();
HibernateUtil.shutdown();
}
}
Transient Object
Transient objects exist in heap memory. Hibernate does not manage transient objects or
persist changes to transient objects.
To persist the changes to a transient object, you would have to ask the session to save
the transient object to the database, at which point Hibernate assigns the object an
identifier and marks the object as being in persistent state.
Persistent Object
Persistent objects exist in the database, and Hibernate manages the persistence for
persistent objects.
If fields or properties change on a persistent object, Hibernate will keep the database
representation up to date when the application marks the changes as to be committed.
Detached Object
Detached objects have a representation in the database, but changes to the object will
not be reflected in the database, and vice-versa. This temporary separation of the object
and the database is shown in image below.
A detached object can be created by closing the session that it was associated with, or
by evicting it from the session with a call to the session’s evict() method.
Removed Object
Removed objects are objects that are being managed by Hibernate (persistent objects,
in other words) that have been passed to the session’s remove() method. When the
application marks the changes held in the session as to be committed, the entries in the
database that correspond to removed objects are deleted.
7. Hibernate Entities Equality and Identity
➔ Object fetched from same session:
sessionOne.getTransaction().commit();
//Get employee id
Integer genEmpId = emp.getEmployeeId();
//New session where we will fetch the employee two times and compare the
objects
Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
sessionTwo.beginTransaction();
//Checking equality
System.out.println(employeeObj1 == employeeObj2);
HibernateUtil.shutdown();
}
Output:
true
System.out.println(emp == employeeObj1);
System.out.println(emp.equals(employeeObj1));
Output:
false
false
@Entity
@Table(name = "Employee")
public class EmployeeEntity implements Serializable
{
private static final long serialVersionUID = -1798070786993154676L;
@Id
@Column(name = "ID", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer employeeId;
@Column(name = "FIRST_NAME", unique = false, nullable = false, length
= 100)
private String firstName;
@Column(name = "LAST_NAME", unique = false, nullable = false, length
= 100)
private String lastName;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EmployeeEntity)) return false;
if (getEmployeeId() != null ?
!getEmployeeId().equals(otherEmployee.getEmployeeId()) :
otherEmployee.getEmployeeId() != null)
return false;
if (getFirstName() != null ?
!getFirstName().equals(otherEmployee.getFirstName()) :
otherEmployee.getFirstName() != null)
return false;
if (getLastName() != null ?
!getLastName().equals(otherEmployee.getLastName()) :
otherEmployee.getLastName() != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = getEmployeeId() != null ? getEmployeeId().hashCode() : 0;
result = 31 * result + (getFirstName() != null ?
getFirstName().hashCode() : 0);
result = 31 * result + (getLastName() != null?getLastName().hashCode()
: 0);
return result;
}
//Setters and Getters
}
Now lets again check the equality using equals() method. [‘==’ will return false, we
know that].
System.out.println(emp.equals(employeeObj1));
Output:
true
In this example you will learn how to map one-to-one relationship using Hibernate
Annotations. Consider the following relationship between Student and Address entity.
To create this relationship you need to have a STUDENT and ADDRESS table. The relational
model is shown below.
@Entity
@Table(name = "STUDENT")
public class Student {
private long studentId;
private String studentName;
private Address studentAddress;
public Student() {
}
@Id
@GeneratedValue
@Column(name = "STUDENT_ID")
public long getStudentId() {
return this.studentId;
}
@OneToOne(cascade = CascadeType.ALL)
public Address getStudentAddress() {
return this.studentAddress;
}
@Entity
@Table(name = "ADDRESS")
public class Address {
public Address() {
}
@Id
@GeneratedValue
@Column(name = "ADDRESS_ID")
public long getAddressId() {
return this.addressId;
}
On executing the Main class you will see the following output.
Each student record points to a different address record, this illustrates the one-to-one
mapping.
9. One to Many:
In this example you will learn how to map one-to-many relationship using
Hibernate Annotations. Consider the following relationship
between Student and Phone entity.
According to the relationship a student can have any number of phone numbers.
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "STUDENT")
public class Student {
public Student() {
}
@Id
@GeneratedValue
@Column(name = "STUDENT_ID")
public long getStudentId() {
return this.studentId;
}
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "STUDENT_PHONE", joinColumns = { @JoinColumn(name = "STUDENT
_ID") }, inverseJoinColumns = { @JoinColumn(name = "PHONE_ID") })
public Set<Phone> getStudentPhoneNumbers() {
return this.studentPhoneNumbers;
}
public void setStudentPhoneNumbers(Set<Phone> studentPhoneNumbers) {
this.studentPhoneNumbers = studentPhoneNumbers;
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "PHONE")
public class Phone {
public Phone() {
}
@Id
@GeneratedValue
@Column(name = "PHONE_ID")
public long getPhoneId() {
return this.phoneId;
}
import java.util.HashSet;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.vaannila.util.HibernateUtil;
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
On executing the Main class you will see the following output.
The STUDENT_PHONE table has two records to link the student and phone numbers.
A single student record points to two phone numbers, this illustrates the one-to-many
mapping.
According to the relationship many students can have the same address.
To create this relationship you need to have a STUDENT and ADDRESS table. The relational
model is shown below.
Student class
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "STUDENT")
public class Student {
private long studentId;
private String studentName;
private Address studentAddress;
public Student() {
}
public Student(String studentName, Address studentAddress) {
this.studentName = studentName;
this.studentAddress = studentAddress;
}
@Id
@GeneratedValue
@Column(name = "STUDENT_ID")
public long getStudentId() {
return this.studentId;
}
public void setStudentId(long studentId) {
this.studentId = studentId;
}
@Column(name = "STUDENT_NAME", nullable = false, length = 100)
public String getStudentName() {
return this.studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
@ManyToOne(cascade = CascadeType.ALL)
public Address getStudentAddress() {
return this.studentAddress;
}
public void setStudentAddress(Address studentAddress) {
this.studentAddress = studentAddress;
}
}
Address class:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "ADDRESS")
public class Address {
private long addressId;
private String street;
private String city;
private String state;
private String zipcode;
public Address() {
}
public Address(String street, String city, String state, String zipcode) {
this.street = street;
this.city = city;
this.state = state;
this.zipcode = zipcode;
}
@Id
@GeneratedValue
@Column(name = "ADDRESS_ID")
public long getAddressId() {
return this.addressId;
}
public void setAddressId(long addressId) {
this.addressId = addressId;
}
@Column(name = "ADDRESS_STREET", nullable = false, length=250)
public String getStreet() {
return this.street;
}
public void setStreet(String street) {
this.street = street;
}
@Column(name = "ADDRESS_CITY", nullable = false, length=50)
public String getCity() {
return this.city;
}
public void setCity(String city) {
this.city = city;
}
@Column(name = "ADDRESS_STATE", nullable = false, length=50)
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
@Column(name = "ADDRESS_ZIPCODE", nullable = false, length=10)
public String getZipcode() {
return this.zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
}
Main class:
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.vaannila.util.HibernateUtil;
public class Main {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
Address address = new Address("OMR Road", "Chennai", "TN", "600097");
//By using cascade=all option the address need not be saved explicitly when t
he student object is persisted the address will be automatically saved.
//session.save(address);
Student student1 = new Student("Eswar", address);
Student student2 = new Student("Joe", address);
session.save(student1);
session.save(student2);
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
On executing the Main class you will see the following output.
According to the relationship a student can enroll in any number of courses and the
course can have any number of students.
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name = "STUDENT")
public class Student {
public Student() {
}
@Id
@GeneratedValue
@Column(name = "STUDENT_ID")
public long getStudentId() {
return this.studentId;
}
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "STUDENT_COURSE", joinColumns = { @JoinColumn(name = "STUDEN
T_ID") }, inverseJoinColumns = { @JoinColumn(name = "COURSE_ID") })
public Set<Course> getCourses() {
return this.courses;
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="COURSE")
public class Course {
public Course() {
}
@Id
@GeneratedValue
@Column(name="COURSE_ID")
public long getCourseId() {
return this.courseId;
}
@Column(name="COURSE_NAME", nullable=false)
public String getCourseName() {
return this.courseName;
}
import java.util.HashSet;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.vaannila.util.HibernateUtil;
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
On executing the Main class you will see the following output.
Each student has enrolled in the same two courses, this illustrates the many-to-many
mapping.
12. @GeneratedValue:
The @GeneratedValue annotation is to configure the way of increment of the specified
column(field). For example when using Mysql, you may specify auto_increment in the
definition of table to make it self-incremental, and then use
@GeneratedValue(strategy = GenerationType.IDENTITY)
Or using Sequence:
@Id
@SequenceGenerator(name="seq",sequenceName="oracle_seq")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
private Integer pid;
@Entity
@Table(name = "CHILD")
public class Child {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long childId;
@Column(name = "CHILD_NAME")
private String childName;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "TOYS")
public class Toy {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "TOY_ID")
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((toyName == null) ? 0 : toyName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Toy other = (Toy) obj;
if (toyName == null) {
if (other.toyName != null)
return false;
} else if (!toyName.equals(other.toyName))
return false;
return true;
}
@Override
public String toString() {
return "Toy [toyId=" + toyId + ", toyName=" + toyName + "]";
}
}
If we still want to fetch data for toys (i.e. eager) then use Hibernate
template's initialize() method.
Normal (lazy):
public Child getChildByIdWithoutToys(Long childId) {
return getHibernateTemplate().get(Child.class, childId);
}
Eager:
public Child getChildByIdWithToys(Long childId) {
Child child = getChildByIdWithoutToys(childId);
getHibernateTemplate().initialize(child.getToyList());
return child;
}
HQL is a language with its own syntax and grammar. It is written as strings, like “from
Product p“. HQL queries are translated by Hibernate into conventional SQL
queries. Hibernate also provides an API that allows us to directly issue SQL queries as well.
An HQL INSERT cannot be used to directly insert arbitrary entities—it can only be used to insert entities constructed from
information obtained from SELECT queries (unlike ordinary SQL, in which an INSERT command can
be used to insert arbitrary data into a table, as well as insert values selected from other tables).
➔ hql select:
String hql = "FROM Employee";
Query query = session.createQuery(hql);
List results = query.list();
String hql = "FROM Employee E WHERE E.id > 10 ORDER BY E.salary DESC";
Query query = session.createQuery(hql);
List results = query.list();
Pagination:
String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(1);
query.setMaxResults(10);
List results = query.list();
16. Criteria:
Following is the simplest example of a criteria query is one, which will simply return
every object that corresponds to the Employee class.
Criteria cr = session.createCriteria(Employee.class);
List results = cr.list();
Restriction:
Criteria cr = session.createCriteria(Employee.class);
cr.add(Restrictions.eq("salary", 2000));
List results = cr.list();
Criteria cr = session.createCriteria(Employee.class);
Criteria cr = session.createCriteria(Employee.class);
➔ The loaded entity can be removed from session using evict() method. The next
loading of this entity will again make a database call if it has been removed using
evict() method.
➔ The whole session cache can be removed using clear() method. It will remove all
the entities stored in cache.
session.getTransaction().commit();
HibernateUtil.shutdown();
Output:
Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_
from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource
sessionTemp.getTransaction().commit();
HibernateUtil.shutdown();
}
Output:
session.evict(department);
//session.clear();
Output:
@Entity
@Table(name = "STUDENT")
public class Student {
@Id
@GeneratedValue
@Column(name = "STUDENT_ID")
private long id;
@Entity
@Table(name = "ADDRESS")
public class Address {
@Id
@Column(name="ADDRESS_ID")
@GeneratedValue(generator="gen")
@GenericGenerator(name="gen", strategy="foreign",parameters=@Parameter(name="property",
value="student"))
private long id;
@OneToOne
@PrimaryKeyJoinColumn
private Student student;
…
…
…
}
Note that now we have a student property in Address class and address property in
Student class, which means we can now navigate in either direction.In hibernate, for
bidirectional relationships like this, we have a concept of ownership, means who is the
owner of this relationship.Put simply, who is responsible for updating the column in DB
on which this relationship depends on. In our case it’s the student_id of Student table
which is driving the complete relationship truck. So we should tell hibernate that it’s the
Student class which will manage the relationship.
@OneToOne
@PrimaryKeyJoinColumn
private Student student;
Which simply says that both the Address table and Student table share the same
primary key.
@Column(unique = true)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private ProductSerialMask mask;
@Column(unique = true)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private Group group;
This code implies that both mask and group have to be unique, but separately. That means
that if, for example, you have a record with a mask.id = 1 and tries to insert another record
with mask.id = 1, you'll get an error, because that column should have unique values. The
same aplies for group.
If you'd like to have both mask and group to be unique separately and to that at class level,
you'd have to write the code as following:
@Table(
name = "product_serial_group_mask",
uniqueConstraints = {
@UniqueConstraint(columnNames = "mask"),
@UniqueConstraint(columnNames = "group")
}
)
hibernate.hbm2ddl.auto" value="update will not modify a db column that has already been
created.
You'll need to backup the table data, drop it and restart your application to get that table's
schema back in sync with your entity. Then reload your data.