Hibernate - ORM Overview: What Is JDBC?
Hibernate - ORM Overview: What Is JDBC?
What is JDBC?
JDBC stands for Java Database Connectivity. It provides a set of Java API for
accessing the relational databases from Java program. These Java APIs enables
Java programs to execute SQL statements and interact with any SQL compliant
database.
JDBC provides a flexible architecture to write a database independent application
that can run on different platforms and interact with different DBMS without any
modification.
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.first_name = fname;
this.last_name = lname;
this.salary = salary;
}
public int getId() {
return id;
}
Consider the above objects are to be stored and retrieved into the following RDBMS
table −
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
First problem, what if we need to modify the design of our database after having
developed a few pages or our application? Second, loading and storing objects in a
relational database exposes us to the following five mismatch problems −
1
Granularity
Sometimes you will have an object model, which has more classes than the number of
corresponding tables in the database.
2
Inheritance
RDBMSs do not define anything similar to Inheritance, which is a natural paradigm in object-
oriented programming languages.
3
Identity
An RDBMS defines exactly one notion of 'sameness': the primary key. Java, however, defines
both object identity (a==b) and object equality (a.equals(b)).
4
Associations
Object-oriented languages represent associations using object references whereas an
RDBMS represents an association as a foreign key column.
5
Navigation
The ways you access objects in Java and in RDBMS are fundamentally different.
What is ORM?
ORM stands for Object-Relational Mapping (ORM) is a programming technique for
converting data between relational databases and object oriented programming
languages such as Java, C#, etc.
An ORM system has the following advantages over plain JDBC −
Sr.No Advantages
.
Sr.No Solutions
.
1 An API to perform basic CRUD operations on objects of persistent classes.
2 A language or API to specify queries that refer to classes and properties of classes.
4 A technique to interact with transactional objects to perform dirty checking, lazy association
fetching, and other optimization functions.
Hibernate - Overview
Hibernate is an Object-Relational Mapping (ORM) solution for JAVA. It is an open
source persistent framework created by Gavin King in 2001. It is a powerful, high
performance Object-Relational Persistence and Query service for any Java
Application.
Hibernate maps Java classes to database tables and from Java data types to SQL
data types and relieves the developer from 95% of common data persistence
related programming tasks.
Hibernate sits between traditional Java objects and database server to handle all
the works in persisting those objects based on the appropriate O/R mechanisms
and patterns.
Hibernate Advantages
Hibernate takes care of mapping Java classes to database tables using XML files and
without writing any line of code.
Provides simple APIs for storing and retrieving Java objects directly to and from the
database.
If there is change in the database or in any table, then you need to change the XML file
properties only.
Abstracts away the unfamiliar SQL types and provides a way to work around familiar
Java Objects.
Hibernate does not require an application server to operate.
Manipulates Complex associations of objects of your database.
Minimizes database access with smart fetching strategies.
Provides simple querying of data.
Supported Databases
Hibernate supports almost all the major RDBMS. Following is a list of few of the
database engines supported by Hibernate −
Supported Technologies
Hibernate supports a variety of other technologies, including −
XDoclet Spring
J2EE
Eclipse plug-ins
Maven
Hibernate - Architecture
Hibernate has a layered architecture which helps the user to operate without having
to know the underlying APIs. Hibernate makes use of the database and
configuration data to provide persistence services (and persistent objects) to the
application.
Following is a very high level view of the Hibernate Application Architecture.
Configuration Object
The Configuration object is the first Hibernate object you create in any Hibernate
application. It is usually created only once during application initialization. It
represents a configuration or properties file required by the Hibernate.
The Configuration object provides two keys components −
Database Connection − This is handled through one or more configuration files
supported by Hibernate. These files are hibernate.properties and hibernate.cfg.xml.
Class Mapping Setup − This component creates the connection between the Java
classes and database tables.
SessionFactory Object
Configuration object is used to create a SessionFactory object which in turn
configures Hibernate for the application using the supplied configuration file and
allows for a Session object to be instantiated. The SessionFactory is a thread safe
object and used by all the threads of an application.
The SessionFactory is a heavyweight object; it is usually created during application
start up and kept for later use. You would need one SessionFactory object per
database using a separate configuration file. So, if you are using multiple
databases, then you would have to create multiple SessionFactory objects.
Session Object
A Session is used to get a physical connection with a database. The Session object
is lightweight and designed to be instantiated each time an interaction is needed
with the database. Persistent objects are saved and retrieved through a Session
object.
The session objects should not be kept open for a long time because they are not
usually thread safe and they should be created and destroyed them as needed.
Transaction Object
A Transaction represents a unit of work with the database and most of the RDBMS
supports transaction functionality. Transactions in Hibernate are handled by an
underlying transaction manager and transaction (from JDBC or JTA).
This is an optional object and Hibernate applications may choose not to use this
interface, instead managing transactions in their own application code.
Query Object
Query objects use SQL or Hibernate Query Language (HQL) string to retrieve data
from the database and create objects. A Query instance is used to bind query
parameters, limit the number of results returned by the query, and finally to execute
the query.
Criteria Object
Criteria objects are used to create and execute object oriented criteria queries to
retrieve objects.
Hibernate - Environment
This chapter explains how to install Hibernate and other associated packages to
prepare an environment for the Hibernate applications. We will work with MySQL
database to experiment with Hibernate examples, so make sure you already have a
setup for MySQL database. For more detail on MySQL, you can check our MySQL
Tutorial.
Downloading Hibernate
It is assumed that you already have the latest version of Java installed on your
system. Following are the simple steps to download and install Hibernate on your
system −
Make a choice whether you want to install Hibernate on Windows, or Unix and then
proceed to the next step to download .zip file for windows and .tz file for Unix.
Download the latest version of Hibernate from http://www.hibernate.org/downloads.
At the time of writing this tutorial, I downloaded hibernate-distribution3.6.4.Final and
when you unzip the downloaded file, it will give you directory structure as shown in the
following image
Installing Hibernate
Once you downloaded and unzipped the latest version of the Hibernate Installation
file, you need to perform following two simple steps. Make sure you are setting your
CLASSPATH variable properly otherwise you will face problem while compiling your
application.
Now, copy all the library files from /lib into your CLASSPATH, and change your
classpath variable to include all the JARs −
Finally, copy hibernate3.jar file into your CLASSPATH. This file lies in the root directory
of the installation and is the primary JAR that Hibernate needs to do its work.
Hibernate Prerequisites
Following is the list of the packages/libraries required by Hibernate and you should
install them before starting with Hibernate. To install these packages, you will have
to copy library files from /lib into your CLASSPATH, and change your CLASSPATH
variable accordingly.
Sr.No Packages/Libraries
.
1
dom4j
XML parsing www.dom4j.org/
2
Xalan
XSLT Processor https://xml.apache.org/xalan-j/
3
Xerces
The Xerces Java Parser https://xml.apache.org/xerces-j/
4
cglib
Appropriate changes to Java classes at runtime http://cglib.sourceforge.net/
5
log4j
Logging Faremwork https://logging.apache.org/log4j
6
Commons
Logging, Email etc. https://jakarta.apache.org/commons
7
SLF4J
Logging Facade for Java https://www.slf4j.org
Hibernate - Configuration
Hibernate requires to know in advance — where to find the mapping information
that defines how your Java classes relate to the database tables. Hibernate also
requires a set of configuration settings related to database and other related
parameters. All such information is usually supplied as a standard Java properties
file called hibernate.properties, or as an XML file named hibernate.cfg.xml.
I will consider XML formatted file hibernate.cfg.xml to specify required Hibernate
properties in my examples. Most of the properties take their default values and it is
not required to specify them in the property file unless it is really required. This file is
kept in the root directory of your application's classpath.
Hibernate Properties
Following is the list of important properties, you will be required to configure for a
databases in a standalone situation −
1
hibernate.dialect
This property makes Hibernate generate the appropriate SQL for the chosen database.
2
hibernate.connection.driver_class
The JDBC driver class.
3
hibernate.connection.url
The JDBC URL to the database instance.
4
hibernate.connection.username
The database username.
5
hibernate.connection.password
The database password.
6
hibernate.connection.pool_size
Limits the number of connections waiting in the Hibernate database connection pool.
7
hibernate.connection.autocommit
Allows autocommit mode to be used for the JDBC connection.
If you are using a database along with an application server and JNDI, then you
would have to configure the following properties −
1
hibernate.connection.datasource
The JNDI name defined in the application server context, which you are using for the
application.
2
hibernate.jndi.class
The InitialContext class for JNDI.
3
hibernate.jndi.<JNDIpropertyname>
Passes any JNDI property you like to the JNDI InitialContext.
4
hibernate.jndi.url
Provides the URL for JNDI.
5
hibernate.connection.username
The database username.
6
hibernate.connection.password
The database password.
</session-factory>
</hibernate-configuration>
1
DB2
org.hibernate.dialect.DB2Dialect
2
HSQLDB
org.hibernate.dialect.HSQLDialect
3
HypersonicSQL
org.hibernate.dialect.HSQLDialect
4
Informix
org.hibernate.dialect.InformixDialect
5
Ingres
org.hibernate.dialect.IngresDialect
6
Interbase
org.hibernate.dialect.InterbaseDialect
7
Microsoft SQL Server 2000
org.hibernate.dialect.SQLServerDialect
8
Microsoft SQL Server 2005
org.hibernate.dialect.SQLServer2005Dialect
9
Microsoft SQL Server 2008
org.hibernate.dialect.SQLServer2008Dialect
10
MySQL
org.hibernate.dialect.MySQLDialect
11
Oracle (any version)
org.hibernate.dialect.OracleDialect
12
Oracle 11g
org.hibernate.dialect.Oracle10gDialect
13
Oracle 10g
org.hibernate.dialect.Oracle10gDialect
14
Oracle 9i
org.hibernate.dialect.Oracle9iDialect
15
PostgreSQL
org.hibernate.dialect.PostgreSQLDialect
16
Progress
org.hibernate.dialect.ProgressDialect
17
SAP DB
org.hibernate.dialect.SAPDBDialect
18
Sybase
org.hibernate.dialect.SybaseDialect
19
Sybase Anywhere
org.hibernate.dialect.SybaseAnywhereDialect
Hibernate - Sessions
A Session is used to get a physical connection with a database. The Session object
is lightweight and designed to be instantiated each time an interaction is needed
with the database. Persistent objects are saved and retrieved through a Session
object.
The session objects should not be kept open for a long time because they are not
usually thread safe and they should be created and destroyed them as needed. The
main function of the Session is to offer, create, read, and delete operations for
instances of mapped entity classes.
Instances may exist in one of the following three states at a given point in time −
transient − A new instance of a persistent class, which is not associated with a Session
and has no representation in the database and no identifier value is considered transient
by Hibernate.
persistent − You can make a transient instance persistent by associating it with a
Session. A persistent instance has a representation in the database, an identifier value
and is associated with a Session.
detached − Once we close the Hibernate Session, the persistent instance will become a
detached instance.
A Session instance is serializable if its persistent classes are serializable. A typical
transaction should use the following idiom −
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
// do some work
...
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
If the Session throws an exception, the transaction must be rolled back and the
session must be discarded.
2
void cancelQuery()
Cancel the execution of the current query.
3
void clear()
Completely clear the session.
4
Connection close()
End the session by releasing the JDBC connection and cleaning up.
5
Criteria createCriteria(Class persistentClass)
Create a new Criteria instance, for the given entity class, or a superclass of an entity class.
6
Criteria createCriteria(String entityName)
Create a new Criteria instance, for the given entity name.
7
Serializable getIdentifier(Object object)
Return the identifier value of the given entity as associated with this session.
8
Query createFilter(Object collection, String queryString)
Create a new instance of Query for the given collection and filter string.
9
Query createQuery(String queryString)
Create a new instance of Query for the given HQL query string.
10
SQLQuery createSQLQuery(String queryString)
Create a new instance of SQLQuery for the given SQL query string.
11
void delete(Object object)
Remove a persistent instance from the datastore.
12
void delete(String entityName, Object object)
Remove a persistent instance from the datastore.
13
Session get(String entityName, Serializable id)
Return the persistent instance of the given named entity with the given identifier, or null if
there is no such persistent instance.
14
SessionFactory getSessionFactory()
Get the session factory which created this session.
15
void refresh(Object object)
Re-read the state of the given instance from the underlying database.
16
Transaction getTransaction()
Get the Transaction instance associated with this session.
17
boolean isConnected()
Check if the session is currently connected.
18
boolean isDirty()
Does this session contain any changes which must be synchronized with the database?
19
boolean isOpen()
Check if the session is still open.
20
Serializable save(Object object)
Persist the given transient instance, first assigning a generated identifier.
21
void saveOrUpdate(Object object)
Either save(Object) or update(Object) the given instance.
22
void update(Object object)
Update the persistent instance with the identifier of the given detached instance.
23
void update(String entityName, Object object)
Update the persistent instance with the identifier of the given detached instance.
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public Employee() {}
There would be one table corresponding to each object you are willing to provide
persistence. Consider above objects need to be stored and retrieved into the
following RDBMS table −
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
Based on the two above entities, we can define following mapping file, which
instructs Hibernate how to map the defined class or classes to the database tables.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
</class>
</hibernate-mapping>
You should save the mapping document in a file with the format
<classname>.hbm.xml. We saved our mapping document in the file
Employee.hbm.xml.
Let us see understand a little detail about the mapping elements used in the
mapping file −
The mapping document is an XML document having <hibernate-mapping> as the root
element, which contains all the <class> elements.
The <class> elements are used to define specific mappings from a Java classes to the
database tables. The Java class name is specified using the name attribute of the class
element and the database table name is specified using the table attribute.
The <meta> element is optional element and can be used to create the class
description.
The <id> element maps the unique ID attribute in class to the primary key of the
database table. The name attribute of the id element refers to the property in the class
and the column attribute refers to the column in the database table. The type attribute
holds the hibernate mapping type, this mapping types will convert from Java to SQL
data type.
The <generator> element within the id element is used to generate the primary key
values automatically. The class attribute of the generator element is set to native to let
hibernate pick up either identity, sequence, or hilo algorithm to create primary key
depending upon the capabilities of the underlying database.
The <property> element is used to map a Java class property to a column in the
database table. The name attribute of the element refers to the property in the class and
the column attribute refers to the column in the database table. The type attribute holds
the hibernate mapping type, this mapping types will convert from Java to SQL data type.
There are other attributes and elements available, which will be used in a mapping
document and I would try to cover as many as possible while discussing other
Hibernate related topics.
Primitive Types
Mapping type Java type ANSI SQL Type
serializable any Java class that implements java.io.Serializable VARBINARY (or BLOB)
JDK-related Types
Mapping type Java type ANSI SQL Type
Hibernate - Examples
Let us now take an example to understand how we can use Hibernate to provide
Java persistence in a standalone application. We will go through the different steps
involved in creating a Java Application using Hibernate technology.
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
</class>
</hibernate-mapping>
You should save the mapping document in a file with the format
<classname>.hbm.xml. We saved our mapping document in the file
Employee.hbm.xml. Let us see little detail about the mapping document −
The mapping document is an XML document having <hibernate-mapping> as the root
element which contains all the <class> elements.
The <class> elements are used to define specific mappings from a Java classes to the
database tables. The Java class name is specified using the name attribute of the class
element and the database table name is specified using the table attribute.
The <meta> element is optional element and can be used to create the class
description.
The <id> element maps the unique ID attribute in class to the primary key of the
database table. The name attribute of the id element refers to the property in the class
and the column attribute refers to the column in the database table. The type attribute
holds the hibernate mapping type, this mapping types will convert from Java to SQL
data type.
The <generator> element within the id element is used to generate the primary key
values automatically. The class attribute of the generator element is set to native to let
hibernate pick up either identity, sequence or hilo algorithm to create primary key
depending upon the capabilities of the underlying database.
The <property> element is used to map a Java class property to a column in the
database table. The name attribute of the element refers to the property in the class and
the column attribute refers to the column in the database table. The type attribute holds
the hibernate mapping type, this mapping types will convert from Java to SQL data type.
There are other attributes and elements available, which will be used in a mapping
document and I would try to cover as many as possible while discussing other
Hibernate related topics.
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
try {
factory = new
Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory
object." + ex);
throw new ExceptionInInitializerError(ex);
}
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
try {
tx = session.beginTransaction();
List employees = session.createQuery("FROM
Employee").list();
for (Iterator iterator = employees.iterator();
iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " +
employee.getFirstName());
System.out.print(" Last Name: " +
employee.getLastName());
System.out.println(" Salary: " +
employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
try {
tx = session.beginTransaction();
Employee employee =
(Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
try {
tx = session.beginTransaction();
Employee employee =
(Employee)session.get(Employee.class, EmployeeID);
session.delete(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
If you check your EMPLOYEE table, it should have the following records −
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara | Ali | 5000 |
| 31 | John | Paul | 10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec
mysql>
Mapping of collections,
Mapping of associations between entity classes, and
Component Mappings.
Collections Mappings
If an entity or class has collection of values for a particular variable, then we can
map those values using any one of the collection interfaces available in java.
Hibernate can persist instances of java.util.Map, java.util.Set,
java.util.SortedMap, java.util.SortedSet, java.util.List, and any array of
persistent entities or values.
1 java.util.Set
2 java.util.SortedSet
This is mapped with a <set> element and initialized with java.util.TreeSet. The sort attribute
can be set to either a comparator or natural ordering.
3 java.util.List
This is mapped with a <list> element and initialized with java.util.ArrayList
4 java.util.Collection
This is mapped with a <bag> or <ibag> element and initialized with java.util.ArrayList
5 java.util.Map
This is mapped with a <map> element and initialized with java.util.HashMap
6 java.util.SortedMap
This is mapped with a <map> element and initialized with java.util.TreeMap.
The sort attribute can be set to either a comparator or natural ordering.
Arrays are supported by Hibernate with <primitive-array> for Java primitive value
types and <array> for everything else. However, they are rarely used, so I am not
going to discuss them in this tutorial.
If you want to map a user defined collection interfaces, which is not directly
supported by Hibernate, you need to tell Hibernate about the semantics of your
custom collections, which is not very easy and not recommend to be used.
Association Mappings
The mapping of associations between entity classes and the relationships between
tables is the soul of ORM. Following are the four ways in which the cardinality of the
relationship between the objects can be expressed. An association mapping can be
unidirectional as well as bidirectional.
1 Many-to-One
2 One-to-One
Mapping one-to-one relationship using Hibernate
3 One-to-Many
Mapping one-to-many relationship using Hibernate
4 Many-to-Many
Mapping many-to-many relationship using Hibernate
Component Mappings
It is very much possible that an Entity class can have a reference to another class
as a member variable. If the referred class does not have its own life cycle and
completely depends on the life cycle of the owning entity class, then the referred
class hence therefore is called as the Component class.
The mapping of Collection of Components is also possible in a similar way just as
the mapping of regular Collections with minor configuration differences. We will see
these two mappings in detail with examples.
1 Component Mappings
Hibernate - Annotations
So far you have seen how Hibernate uses XML mapping file for the transformation
of data from POJO to database tables and vice versa. Hibernate annotations are
the newest way to define mappings without the use of XML file. You can use
annotations in addition to or as a replacement of XML mapping metadata.
Hibernate Annotations is the powerful way to provide the metadata for the Object
and Relational Table mapping. All the metadata is clubbed into the POJO java file
along with the code, this helps the user to understand the table structure and POJO
simultaneously during the development.
If you going to make your application portable to other EJB 3 compliant ORM
applications, you must use annotations to represent the mapping information, but
still if you want greater flexibility, then you should go with XML-based mappings.
Following is the mapping of Employee class with annotations to map objects with
the defined EMPLOYEE table −
import javax.persistence.*;
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@Id @GeneratedValue
@Column(name = "id")
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "salary")
private int salary;
public Employee() {}
Hibernate detects that the @Id annotation is on a field and assumes that it should
access properties of an object directly through fields at runtime. If you placed the
@Id annotation on the getId() method, you would enable access to properties
through getter and setter methods by default. Hence, all other annotations are also
placed on either fields or getter methods, following the selected strategy.
Following section will explain the annotations used in the above class.
@Entity Annotation
The EJB 3 standard annotations are contained in the javax.persistence package,
so we import this package as the first step. Second, we used
the @Entity annotation to the Employee class, which marks this class as an entity
bean, so it must have a no-argument constructor that is visible with at least
protected scope.
@Table Annotation
The @Table annotation allows you to specify the details of the table that will be
used to persist the entity in the database.
The @Table annotation provides four attributes, allowing you to override the name
of the table, its catalogue, and its schema, and enforce unique constraints on
columns in the table. For now, we are using just table name, which is EMPLOYEE.
@Column Annotation
The @Column annotation is used to specify the details of the column to which a
field or property will be mapped. You can use column annotation with the following
most commonly used attributes −
name attribute permits the name of the column to be explicitly specified.
length attribute permits the size of the column used to map a value particularly for a
String value.
nullable attribute permits the column to be marked NOT NULL when the schema is
generated.
unique attribute permits the column to be marked as containing only unique values.
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
try {
factory = new AnnotationConfiguration().
configure().
//addPackage("com.xyz") //add package if used.
addAnnotatedClass(Employee.class).
buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory
object." + ex);
throw new ExceptionInInitializerError(ex);
}
try {
tx = session.beginTransaction();
Employee employee = new Employee();
employee.setFirstName(fname);
employee.setLastName(lname);
employee.setSalary(salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
try {
tx = session.beginTransaction();
List employees = session.createQuery("FROM
Employee").list();
for (Iterator iterator = employees.iterator();
iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " +
employee.getFirstName());
System.out.print(" Last Name: " +
employee.getLastName());
System.out.println(" Salary: " +
employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
try {
tx = session.beginTransaction();
Employee employee =
(Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
try {
tx = session.beginTransaction();
Employee employee =
(Employee)session.get(Employee.class, EmployeeID);
session.delete(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Database Configuration
Now let us create hibernate.cfg.xml configuration file to define database related
parameters.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
</session-factory>
</hibernate-configuration>
If you check your EMPLOYEE table, it should have the following records −
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara | Ali | 5000 |
| 31 | John | Paul | 10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec
mysql>
FROM Clause
You will use FROM clause if you want to load a complete persistent objects into
memory. Following is the simple syntax of using FROM clause −
String hql = "FROM Employee";
Query query = session.createQuery(hql);
List results = query.list();
If you need to fully qualify a class name in HQL, just specify the package and class
name as follows −
String hql = "FROM com.hibernatebook.criteria.Employee";
Query query = session.createQuery(hql);
List results = query.list();
AS Clause
The AS clause can be used to assign aliases to the classes in your HQL queries,
especially when you have the long queries. For instance, our previous simple
example would be the following −
String hql = "FROM Employee AS E";
Query query = session.createQuery(hql);
List results = query.list();
The AS keyword is optional and you can also specify the alias directly after the
class name, as follows −
String hql = "FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();
SELECT Clause
The SELECT clause provides more control over the result set then the from clause.
If you want to obtain few properties of objects instead of the complete object, use
the SELECT clause. Following is the simple syntax of using SELECT clause to get
just first_name field of the Employee object −
String hql = "SELECT E.firstName FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();
WHERE Clause
If you want to narrow the specific objects that are returned from storage, you use
the WHERE clause. Following is the simple syntax of using WHERE clause −
String hql = "FROM Employee E WHERE E.id = 10";
Query query = session.createQuery(hql);
List results = query.list();
ORDER BY Clause
To sort your HQL query's results, you will need to use the ORDER BY clause. You
can order the results by any property on the objects in the result set either
ascending (ASC) or descending (DESC). Following is the simple syntax of using
ORDER BY clause −
String hql = "FROM Employee E WHERE E.id > 10 ORDER BY E.salary
DESC";
Query query = session.createQuery(hql);
List results = query.list();
If you wanted to sort by more than one property, you would just add the additional
properties to the end of the order by clause, separated by commas as follows −
String hql = "FROM Employee E WHERE E.id > 10 " +
"ORDER BY E.firstName DESC, E.salary DESC ";
Query query = session.createQuery(hql);
List results = query.list();
GROUP BY Clause
This clause lets Hibernate pull information from the database and group it based on
a value of an attribute and, typically, use the result to include an aggregate value.
Following is the simple syntax of using GROUP BY clause −
String hql = "SELECT SUM(E.salary), E.firtName FROM Employee E "
+
"GROUP BY E.firstName";
Query query = session.createQuery(hql);
List results = query.list();
UPDATE Clause
Bulk updates are new to HQL with Hibernate 3, and delete work differently in
Hibernate 3 than they did in Hibernate 2. The Query interface now contains a
method called executeUpdate() for executing HQL UPDATE or DELETE
statements.
The UPDATE clause can be used to update one or more properties of an one or
more objects. Following is the simple syntax of using UPDATE clause −
String hql = "UPDATE Employee set salary = :salary " +
"WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("salary", 1000);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
DELETE Clause
The DELETE clause can be used to delete one or more objects. Following is the
simple syntax of using DELETE clause −
String hql = "DELETE FROM Employee " +
"WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
INSERT Clause
HQL supports INSERT INTO clause only where records can be inserted from one
object to another object. Following is the simple syntax of using INSERT INTO
clause −
String hql = "INSERT INTO Employee(firstName, lastName, salary)"
+
"SELECT firstName, lastName, salary FROM
old_employee";
Query query = session.createQuery(hql);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
Aggregate Methods
HQL supports a range of aggregate methods, similar to SQL. They work the same
way in HQL as in SQL and following is the list of the available functions −
1
avg(property name)
The average of a property's value
2
count(property name or *)
The number of times a property occurs in the results
3
max(property name)
The maximum value of the property values
4
min(property name)
The minimum value of the property values
5
sum(property name)
The sum total of the property values
The distinct keyword only counts the unique values in the row set. The following
query will return only unique count −
String hql = "SELECT count(distinct E.firstName) FROM Employee
E";
Query query = session.createQuery(hql);
List results = query.list();
1
Query setFirstResult(int startPosition)
This method takes an integer that represents the first row in your result set, starting with row
0.
2
Query setMaxResults(int maxResult)
This method tells Hibernate to retrieve a fixed number maxResults of objects.
Using above two methods together, we can construct a paging component in our
web or Swing application. Following is the example, which you can extend to fetch
10 rows at a time −
String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(1);
query.setMaxResults(10);
List results = query.list();
Following are the few more examples covering different scenarios and can be used
as per the requirement −
Criteria cr = session.createCriteria(Employee.class);
Though all the above conditions can be used directly with HQL as explained in
previous tutorial.
1
public Criteria setFirstResult(int firstResult)
This method takes an integer that represents the first row in your result set, starting with row
0.
2
public Criteria setMaxResults(int maxResults)
This method tells Hibernate to retrieve a fixed number maxResults of objects.
Using above two methods together, we can construct a paging component in our
web or Swing application. Following is the example, which you can extend to fetch
10 rows at a time −
Criteria cr = session.createCriteria(Employee.class);
cr.setFirstResult(1);
cr.setMaxResults(10);
List results = cr.list();
public Employee() {}
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
</class>
</hibernate-mapping>
Finally, we will create our application class with the main() method to run the
application where we will use Criteria queries −
import java.util.List;
import java.util.Date;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Projections;
import org.hibernate.cfg.Configuration;
try {
factory = new
Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory
object." + ex);
throw new ExceptionInInitializerError(ex);
}
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
try {
tx = session.beginTransaction();
Criteria cr = session.createCriteria(Employee.class);
try {
tx = session.beginTransaction();
Criteria cr = session.createCriteria(Employee.class);
If you check your EMPLOYEE table, it should have the following records−
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 14 | Zara | Ali | 2000 |
| 15 | Daisy | Das | 5000 |
| 16 | John | Paul | 5000 |
| 17 | Mohd | Yasee | 3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)
mysql>
After you pass a string containing the SQL query to the createSQLQuery() method,
you can associate the SQL result with either an existing Hibernate entity, a join, or a
scalar result using addEntity(), addJoin(), and addScalar() methods respectively.
Scalar Queries
The most basic SQL query is to get a list of scalars (values) from one or more
tables. Following is the syntax for using native SQL for scalar values −
String sql = "SELECT first_name, salary FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List results = query.list();
Entity Queries
The above queries were all about returning scalar values, basically returning the
"raw" values from the result set. Following is the syntax to get entity objects as a
whole from a native sql query via addEntity().
String sql = "SELECT * FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
List results = query.list();
public Employee() {}
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
</class>
</hibernate-mapping>
Finally, we will create our application class with the main() method to run the
application where we will use Native SQL queries −
import java.util.*;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.SQLQuery;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.cfg.Configuration;
try {
factory = new
Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory
object." + ex);
throw new ExceptionInInitializerError(ex);
}
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
try {
tx = session.beginTransaction();
String sql = "SELECT first_name, salary FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List data = query.list();
try {
tx = session.beginTransaction();
String sql = "SELECT * FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
List employees = query.list();
If you check your EMPLOYEE table, it should have the following records −
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 26 | Zara | Ali | 2000 |
| 27 | Daisy | Das | 5000 |
| 28 | John | Paul | 5000 |
| 29 | Mohd | Yasee | 3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)
mysql>
Hibernate - Caching
Caching is a mechanism to enhance the performance of a system. It is a buffer
memorythat lies between the application and the database. Cache memory stores
recently used data items in order to reduce the number of database hits as much as
possible.
Caching is important to Hibernate as well. It utilizes a multilevel caching scheme as
explained below −
First-level Cache
The first-level cache is the Session cache and is a mandatory cache through which
all requests must pass. The Session object keeps an object under its own power
before committing it to the database.
If you issue multiple updates to an object, Hibernate tries to delay doing the update
as long as possible to reduce the number of update SQL statements issued. If you
close the session, all the objects being cached are lost and either persisted or
updated in the database.
Second-level Cache
Second level cache is an optional cache and first-level cache will always be
consulted before any attempt is made to locate an object in the second-level cache.
The second level cache can be configured on a per-class and per-collection basis
and mainly responsible for caching objects across sessions.
Any third-party cache can be used with Hibernate.
An org.hibernate.cache.CacheProvider interface is provided, which must be
implemented to provide Hibernate with a handle to the cache implementation.
Query-level Cache
Hibernate also implements a cache for query resultsets that integrates closely with
the second-level cache.
This is an optional feature and requires two additional physical cache regions that
hold the cached query results and the timestamps when a table was last updated.
This is only useful for queries that are run frequently with the same parameters.
Concurrency Strategies
A concurrency strategy is a mediator, which is responsible for storing items of data
in the cache and retrieving them from the cache. If you are going to enable a
second-level cache, you will have to decide, for each persistent class and collection,
which cache concurrency strategy to use.
Transactional − Use this strategy for read-mostly data where it is critical to prevent stale
data in concurrent transactions, in the rare case of an update.
Read-write − Again use this strategy for read-mostly data where it is critical to prevent
stale data in concurrent transactions, in the rare case of an update.
Nonstrict-read-write − This strategy makes no guarantee of consistency between the
cache and the database. Use this strategy if data hardly ever changes and a small
likelihood of stale data is not of critical concern.
Read-only − A concurrency strategy suitable for data, which never changes. Use it for
reference data only.
If we are going to use second-level caching for our Employee class, let us add the
mapping element required to tell Hibernate to cache Employee instances using
read-write strategy.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
</class>
</hibernate-mapping>
Cache Provider
Your next step after considering the concurrency strategies, you will use your cache
candidate classes to pick a cache provider. Hibernate forces you to choose a single
cache provider for the whole application.
1
EHCache
It can cache in memory or on disk and clustered caching and it supports the optional
Hibernate query result cache.
2
OSCache
Supports caching to memory and disk in a single JVM with a rich set of expiration policies and
query cache support.
3
warmCache
A cluster cache based on JGroups. It uses clustered invalidation, but doesn't support the
Hibernate query cache.
4
JBoss Cache
A fully transactional replicated clustered cache also based on the JGroups multicast library. It
supports replication or invalidation, synchronous or asynchronous communication, and
optimistic and pessimistic locking. The Hibernate query cache is supported.
Every cache provider is not compatible with every concurrency strategy. The
following compatibility matrix will help you choose an appropriate combination.
EHCache X X X
OSCache X X X
SwarmCache X X
JBoss Cache X X
</session-factory>
</hibernate-configuration>
Now, you need to specify the properties of the cache regions. EHCache has its own
configuration file, ehcache.xml, which should be in the CLASSPATH of the
application. A cache configuration in ehcache.xml for the Employee class may look
like this −
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory = "1000"
eternal = "false"
timeToIdleSeconds = "120"
timeToLiveSeconds = "120"
overflowToDisk = "true"
/>
That's it, now we have second-level caching enabled for the Employee class and
Hibernate, now hits the second-level cache whenever you navigate to an Employee
or when you load an Employee by identifier.
You should analyze your all the classes and choose appropriate caching strategy
for each of the classes. Sometime, second-level caching may downgrade the
performance of the application. So, it is recommended to benchmark your
application first, without enabling caching and later on enable your well suited
caching and check the performance. If caching is not improving system
performance, then there is no point in enabling any type of caching.
Hibernate also supports very fine-grained cache support through the concept of a
cache region. A cache region is part of the cache that's given a name.
Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
query.setCacheRegion("employee");
List users = query.list();
SessionFactory.closeSession();
This code uses the method to tell Hibernate to store and look for the query in the
employee area of the cache.
By default, Hibernate will cache all the persisted objects in the session-level cache
and ultimately your application would fall over with
an OutOfMemoryException somewhere around the 50,000th row. You can resolve
this problem, if you are using batch processing with Hibernate.
To use the batch processing feature, first set hibernate.jdbc.batch_size as batch
size to a number either at 20 or 50 depending on object size. This will tell the
hibernate container that every X rows to be inserted as batch. To implement this in
your code, we would need to do little modification as follows −
Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Employee employee = new Employee(.....);
session.save(employee);
if( i % 50 == 0 ) { // Same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Above code will work fine for the INSERT operation, but if you are willing to make
UPDATE operation, then you can achieve using the following code −
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
while ( employeeCursor.next() ) {
Employee employee = (Employee) employeeCursor.get(0);
employee.updateEmployee();
seession.update(employee);
if ( ++count % 50 == 0 ) {
session.flush();
session.clear();
}
}
tx.commit();
session.close();
<hibernate-configuration>
<session-factory>
</session-factory>
</hibernate-configuration>
public Employee() {}
Let us create the following EMPLOYEE table to store the Employee objects −
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
Following will be the mapping file to map the Employee objects with EMPLOYEE
table −
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
</class>
</hibernate-mapping>
Finally, we will create our application class with the main() method to run the
application where we will use flush() and clear() methods available with Session
object so that Hibernate keeps writing these records into the database instead of
caching them in the memory.
import java.util.*;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
try {
factory = new
Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory
object." + ex);
throw new ExceptionInInitializerError(ex);
}
ManageEmployee ME = new ManageEmployee();
try {
tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
String fname = "First Name " + i;
String lname = "Last Name " + i;
Integer salary = i;
Employee employee = new Employee(fname, lname,
salary);
session.save(employee);
if( i % 50 == 0 ) {
session.flush();
session.clear();
}
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return ;
}
}
Hibernate - Interceptors
As you have learnt that in Hibernate, an object will be created and persisted. Once
the object has been changed, it must be saved back to the database. This process
continues until the next time the object is needed, and it will be loaded from the
persistent store.
Thus an object passes through different stages in its life cycle and Interceptor
Interface provides methods, which can be called at different stages to perform
some required tasks. These methods are callbacks from the session to the
application, allowing the application to inspect and/or manipulate properties of a
persistent object before it is saved, updated, deleted or loaded. Following is the list
of all the methods available within the Interceptor interface −
1
findDirty()
This method is be called when the flush() method is called on a Session object.
2
instantiate()
This method is called when a persisted class is instantiated.
3
isUnsaved()
This method is called when an object is passed to the saveOrUpdate() method/
4
onDelete()
This method is called before an object is deleted.
5
onFlushDirty()
This method is called when Hibernate detects that an object is dirty (i.e. have been changed)
during a flush i.e. update operation.
6
onLoad()
This method is called before an object is initialized.
7
onSave()
This method is called before an object is saved.
8
postFlush()
This method is called after a flush has occurred and an object has been updated in memory.
9
preFlush()
This method is called before a flush.
Hibernate Interceptor gives us total control over how an object will look to both the
application and the database.
Create Interceptors
We will extend EmptyInterceptor in our example where Interceptor's method will be
called automatically when Employee object is created and updated. You can
implement more methods as per your requirements.
import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;
public Employee() {}
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
</class>
</hibernate-mapping>
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
try {
factory = new
Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory
object." + ex);
throw new ExceptionInInitializerError(ex);
}
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
try {
tx = session.beginTransaction();
List employees = session.createQuery("FROM
Employee").list();
for (Iterator iterator = employees.iterator();
iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " +
employee.getFirstName());
System.out.print(" Last Name: " +
employee.getLastName());
System.out.println(" Salary: " +
employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
try {
tx = session.beginTransaction();
Employee employee =
(Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
try {
tx = session.beginTransaction();
Employee employee =
(Employee)session.get(Employee.class, EmployeeID);
session.delete(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
If you check your EMPLOYEE table, it should have the following records −
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara | Ali | 5000 |
| 31 | John | Paul | 10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec
mysql>