Hibernate Theory Full
Hibernate Theory Full
What is JDBC?
JDBC stands for Java Database Connectivity and 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;
}
public String getFirstName() {
return first_name;
}
public String getLastName() {
return last_name;
}
public int getSalary() {
return salary;
}
}
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)
);
First problem, what if we need to modify the design of our database after having developed few pages or our application?
Second, Loading and storing objects in a relational database exposes us to the following five mismatch problems.
Mismatch Description
Granularity Sometimes you will have an object model which has more classes than the number of
corresponding tables in the database.
RDBMSs do not define anything similar to Inheritance which is a natural paradigm in object-
Inheritance
oriented programming languages.
A RDBMS defines exactly one notion of 'sameness': the primary key. Java, however, defines
Identity
both object identity (a==b) and object equality (a.equals(b)).
Navigation The ways you access objects in Java and in a RDBMS are fundamentally different.
The Object-Relational Mapping (ORM) is the solution to handle all the above impedance mismatches.
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 following advantages over
plain JDBC
S.N. Advantages
2 A language or API to specify queries that refer to classes and properties of classes.
A technique to interact with transactional objects to perform dirty checking, lazy association fetching, and
4
other optimization functions.
Hibernate Overview
Hibernate is an Object-Relational Mapping(ORM) solution for JAVA and it raised as 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 relieve the
developer from 95% of common data persistence related programming tasks.
Hibernate sits between traditional Java objects and database server to handle all the work 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 Database or in any table then the only need to change XML file properties.
Abstract away the unfamiliar SQL types and provide us to work around familiar Java Objects.
Hibernate does not require an application server to operate.
Manipulates Complex associations of objects of your database.
Minimize database access with smart fetching strategies.
Provides Simple querying of data.
Supported Databases:
Hibernate supports almost all the major RDBMS. Following is list of few of the database engines supported by
Hibernate.
HSQL Database Engine
DB2/NT
MySQL
PostgreSQL
FrontBase
Oracle
Microsoft SQL Server Database
Sybase SQL Server
Informix Dynamic Server
Supported Technologies:
Hibernate supports a variety of other technologies, including the following:
XDoclet Spring
J2EE
Eclipse plug-ins
Maven
Hibernate Architecture
The Hibernate architecture is layered to keep you isolated from 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.
Following is a detailed view of the Hibernate Application Architecture with few important core classes.
Hibernate uses various existing Java APIs, like JDBC, Java Transaction API(JTA), and Java Naming and Directory
Interface (JNDI). JDBC provides a rudimentary level of abstraction of functionality common to relational databases,
allowing almost any database with a JDBC driver to be supported by Hibernate. JNDI and JTA allow Hibernate to be
integrated with J2EE application servers.
Following section gives brief description of each of the class objects involved in Hibernate Application Architecture.
Configuration Object:
The Configuration object is the first Hibernate object you create in any Hibernate application and 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 inturn 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 heavyweight object so usually it is 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 object are used to create and execute object oriented criteria queries to retrieve objects.
Downloading Hibernate:
It is assumed that you already have latest version of Java is installed on your machine. Following are the simple
steps to download and install Hibernate on your machine.
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-distribution-3.6.4.Final and when you unzip the
downloaded file it will give you directory structure as follows.
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 would have to copy library files from /lib into your CLASSPATH, and
change your CLASSPATH variable accordingly.
S.N. Packages/Libraries
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 would require to configure for a databases in a standalone situation:
S.N. Properties and Description
hibernate.dialect
1
This property makes Hibernate generate the appropriate SQL for the chosen database.
hibernate.connection.driver_class
2
The JDBC driver class.
hibernate.connection.url
3
The JDBC URL to the database instance.
hibernate.connection.username
4
The database username.
hibernate.connection.password
5
The database password.
hibernate.connection.pool_size
6
Limits the number of connections waiting in the Hibernate database connection pool.
hibernate.connection.autocommit
7
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:
S.N. Properties and Description
hibernate.connection.datasource
1
The JNDI name defined in the application server context you are using for the application.
hibernate.jndi.class
2
The InitialContext class for JNDI.
hibernate.jndi.<JNDIpropertyname>
3
Passes any JNDI property you like to the JNDI InitialContext.
hibernate.jndi.url
4
Provides the URL for JNDI.
hibernate.connection.username
5
The database username.
hibernate.connection.password
6
The database password.
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
</session-factory>
</hibernate-configuration>
The above configuration file includes <mapping> tags which are related to hibernate-mapping file and we will see in
next chapter what exactly is a hibernate mapping file and how and why do we use it. Following is the list of various
important databases dialect property type:
Database Dialect Property
DB2 org.hibernate.dialect.DB2Dialect
HSQLDB org.hibernate.dialect.HSQLDialect
HypersonicSQL org.hibernate.dialect.HSQLDialect
Informix org.hibernate.dialect.InformixDialect
Ingres org.hibernate.dialect.IngresDialect
Interbase org.hibernate.dialect.InterbaseDialect
MySQL org.hibernate.dialect.MySQLDialect
Oracle 9i org.hibernate.dialect.Oracle9iDialect
PostgreSQL org.hibernate.dialect.PostgreSQLDialect
Progress org.hibernate.dialect.ProgressDialect
SAP DB org.hibernate.dialect.SAPDBDialect
Sybase org.hibernate.dialect.SybaseDialect
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 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.
Transaction beginTransaction()
1
Begin a unit of work and return the associated Transaction object.
void cancelQuery()
2
Cancel the execution of the current query.
void clear()
3
Completely clear the session.
Connection close()
4
End the session by releasing the JDBC connection and cleaning up.
SessionFactory getSessionFactory()
14
Get the session factory which created this session.
Transaction getTransaction()
16
Get the Transaction instance associated with this session.
boolean isConnected()
17
Check if the session is currently connected.
boolean isDirty()
18
Does this session contain any changes which must be synchronized with the database?
boolean isOpen()
19
Check if the session is still open.
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
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">
<meta attribute="class-description">
This class contains the employee detail.
</meta>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</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 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 automatically generate the primary key values. Set
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.
Hibernate Mapping Types
When you prepare a Hibernate mapping document, we have seen that you map Java data types into RDBMS data
types. The types declared and used in the mapping files are not Java data types; they are not SQL database types
either. These types are called Hibernate mapping types, which can translate from Java to SQL data types and vice
versa.
This chapter lists down all the basic, date and time, large object, and various other builtin mapping types.
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 try an example of using Hibernate to provide Java persistence in a standalone application. We will go through
different steps involved in creating Java Application using Hibernate technology.
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Create Database Tables:
Second step would be creating tables in your database. 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)
);
<hibernate-mapping>
<class name="Employee" table="EMPLOYEE">
<meta attribute="class-description">
This class contains the employee detail.
</meta>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</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 automatically generate the primary key values. Set
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.
mysql>
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 ofjava.util.Map, java.util.Set,
java.util.SortedMap, java.util.SortedSet, java.util.List, and any array of persistent entities or values.
Collection type Mapping and Description
java.util.Set This is mapped with a <set> element and initialized with java.util.HashSet
java.util.List This is mapped with a <list> element and initialized with java.util.ArrayList
java.util.Map This is mapped with a <map> element and initialized with java.util.HashMap
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.
Mapping type Description
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 it's 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.
Mapping type Description
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 is the newest way to define mappings without a 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.
@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() {}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Hibernate detects that the @Id annotation is on a field and assumes that it should access properties on 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;
Database Configuration:
Now let us create hibernate.cfg.xml configuration file to define database related parameters. This time we are not
going
<?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>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
</session-factory>
</hibernate-configuration>
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, specially when you have 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 than 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();
It is notable here that Employee.firstName is a property of Employee object rather than a field of the EMPLOYEE
table.
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 deletes 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:
S.N. Functions Description
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Let us create the following EMPLOYEE table to store 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 mapping file.
<?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>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</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;
/* Method to READ all the employees having salary more than 2000 */
public void listEmployees( ){
Session session = factory.openSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
Criteria cr = session.createCriteria(Employee.class);
// Add restriction.
cr.add(Restrictions.gt("salary", 2000));
List employees = cr.list();
mysql>
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 resultset. The
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() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Let us create the following EMPLOYEE table to store 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 mapping file.
<?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>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</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;
mysql>
Hibernate Caching
Caching is all about application performance optimization and it sits between your application and the database to
avoid the number of database hits as many as possible to give a better performance for performance critical
applications.
Caching is important to Hibernate as well which utilizes a multilevel caching schemes 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 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>
<cache usage="read-write"/>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</class>
</hibernate-mapping>
The usage="read-write" attribute tells Hibernate to use a read-write concurrency strategy for the defined cache.
Cache provider:
Your next step after considering the concurrency strategies you will use for your cache candidate classes is to pick a
cache provider. Hibernate forces you to choose a single cache provider for the whole application.
S.N. Cache Name Description
It can cache in memory or on disk and clustered caching and it supports the
1 EHCache
optional Hibernate query result cache.
Supports caching to memory and disk in a single JVM, with a rich set of
2 OSCache
expiration policies and query cache support.
EHCache X X X
OSCache X X X
SwarmCache X X
JBoss Cache X X
You will specify a cache provider in hibernate.cfg.xml configuration file. We choose EHCache as our second-level
cache provider:
<?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>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
</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"
/>
<cache name="Employee"
maxElementsInMemory="500"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
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 a Employee or when you load a 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.
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>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
</session-factory>
</hibernate-configuration>
Consider the following POJO Employee class:
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Let us create the following EMPLOYEE table to store 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 mapping file to map 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">
<meta attribute="class-description">
This class contains the employee detail.
</meta>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</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 keep 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;
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:
S.N. Method and Description
findDirty()
1
This method is be called when the flush() method is called on a Session object.
instantiate()
2
This method is called when a persisted class is instantiated.
isUnsaved()
3
This method is called when an object is passed to the saveOrUpdate() method/
onDelete()
4
This method is called before an object is deleted.
5 onFlushDirty()
This method is called when Hibernate detects that an object is dirty (ie. have been changed)
during a flush i.e. update operation.
onLoad()
6
This method is called before an object is initialized.
onSave()
7
This method is called before an object is saved.
postFlush()
8
This method is called after a flush has occurred and an object has been updated in memory.
preFlush()
9
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() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
<hibernate-mapping>
<class name="Employee" table="EMPLOYEE">
<meta attribute="class-description">
This class contains the employee detail.
</meta>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</class>
</hibernate-mapping>
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
First Name: Zara Last Name: Ali Salary: 1000
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 10000
preFlush
postFlush
preFlush
Update Operation
postFlush
preFlush
postFlush
First Name: Zara Last Name: Ali Salary: 5000
First Name: John Last Name: Paul Salary: 10000
preFlush
postFlush
If you check your EMPLOYEE table, it should have 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>