Persistence:
In core Java
Persistence implies,
using Serializable interface to
permanently store object on the Hard Disk
In Enterprise
Application
Using JDBC API to
store data permanently in database
Process
of storing Enterprise Data in a Relational Database is known as
persistence.
Architecture of an
Enterprise App
Limitations of Traditional Approach
}Business
logic is polluted with data accessing logic. Major role of Business tier is to
concentrate on business logic alone but not on DB connectivity.
}Application
portability to DB is lost.
Eg: SQL
statements developed for one DBMS may or may not work if
the DBMS changes (tightly coupled/ vendor)
}Mismatches
between object oriented Data Model and Relational Model cannot be addressed.
Alternative ways for Traditional
Approach
DAO Approach
}In DAO approach all
possible data access operations are centralised in few Java classes.
ORM
approach
}It is a technique of
mapping object oriented data representation to that of the relational Model.
Hibernate
}Hibernate
is an object relational mapping service implementation.
}Hibernate
is used to build persistent tier for Java based business
applications.
}We can use
Hibernate service through Hibernate API.
Hibernate Architecture
Configuration file & Mapping file:
Mapping file
}It is text file where
Hibernate application develops specify the domain object class name and its
attributes relational table and corresponding column names are also specified
here.
}Mapping object
oriented data representation to relational data.
}Standard name for
this file is “
ClassName.hbm.xml”.
Example:
Employee.Java
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;
}
}
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 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>
Configuration file:
}It’s a
text file which contains all DB connection details (driver, DB, authentication
& connection pooling details)
}Hibernate
uses this file to establish connection to that particular database server and
generates that particular product native SQL code
}Standard
name for this file is “ hibernate.cfg.xml”
Example: hibernate.cfg.xml (for MySQL)
<?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>
<!-- Assume test is the database name -->
<property name="hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<property name="hibernate.connection.username">
root
</property>
<property name="hibernate.connection.password">
root123
</property>
<!-- List of XML mapping files -->
<mapping resource="Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
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 |
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:
S.N. | Properties and Description |
1 | hibernate.connection.datasource
The JNDI name defined in the application server context 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.
|
Configuration, SessionFactory
& session object:
Configuration
}Object oriented
representation of hibernate configuration file along with mapping file is known
as Configuration object.
SessionFactory (like
Connection Factory)
}It is a factory of
session objects. It is similar to data source object. It is heavy weight object
that has to be constructed/created only once for the application.
}sessionFactory object
produce light weight session objects.
Example:
Configuration c= new
Configuration(); c.configure();
//now the file loading takes place.
SessionFactory sf= c.buildSessionFactory();
Session s= sf.openSession();
Session object (like connection):
Session object is
the persistence manager for the Hibernate application.
Session object
provides the following methods to perform CRUD operations.}get/load (for
retrieving a record)}update()
(for updating a record)}delete() (for deleting a record)}save() (for inserting a record)
Entity Relationships:
}In relational model,
entities(tables) are associated with the PrimaryKey – ForiegnKey
relationship.
}In object oriented
model, one persistent class is associated with other persistent class through
object references made as data members.
We have 4 kinds of relationships
}one to
one
}one to
many
}many to
one
}many to
many
Example:
}One-to-One (1:1) – one employee works for one department.
}One-to-Many (1:N) or Many-to-One (N:1) depending upon from which perspective we are looking at the relationship. One employee works in many projects.
}Many-to-Many (N:M) – Many books are written by many authors.
HQL (Hibernate Query Language):
}To perform complex persistent
operations, Session object provided normal methods which are not sufficient. They can act upon only
one persistent object (i.e one record only).
}HQL is used to deal with multiple persistent objects with
different criteria in DBMS independent manner.
}HQL is similar to SQL query with one major difference.
}SQL query is
expressed in terms of table’s and column’s.
}HQL query is
expressed in terms of persistent classes and their attributes.
Example:
String hql = “FROM
Employee”;
Query query = session.createQuery(hql);
List result = query.list();
Query query1= Session.createQuery(“UPDATE
Account a set a.balance = a.balance +
1000”);
we can also specify
place holder in place of values. These are known as parameters of the query.
Query query2 = Session.createQuery(“ SELECT
a FROM Account a where a.account=?”);
Query1.setParameter(0,accno);
List <Account>
accounts = query1.list();
- Keywords
like SELECT , FROM and WHERE etc. are not case sensitive but properties like
table and column names are case sensitive in HQL.
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:
Eg: 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:
Eg: 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:
Eg: 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:
Eg: 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:
Eg: 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:
Eg: String
hql = "FROM Employee E WHERE E.id = 10 and e.salay >=10001";
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:
Eg: 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:
Eg: 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:
Eg: String
hql = "SELECT SUM(E.salary), E.firtName FROM Employee E " +
Query
query = session.createQuery(hql);
List
results = query.list();
Using Named Paramters:
Hibernate
supports named parameters in its HQL queries. This makes writing HQL queries
that accept input from the user easy and you do not have to defend against SQL
injection attacks. Following is the simple syntax of using named parameters:
Eg: String
hql = "FROM Employee E WHERE E.id = :employee_id";
Query
query = session.createQuery(hql);
query.setParameter("employee_id",10);
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:
Eg: 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:
Eg: 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:
Eg: 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);
Named Query:
Employee.hbm.xml
}<query name = “salRange”>
FROM Employee e WHERE
e.salary BETWEEN :lower AND :upper </query>
In Java class
}Query q = session.getNamedQuery(“salRange”);
}q.setParameter(“lower”, 10000);
}q.setParameter(“upper”, 50000);
}List<Employee> l = q.list();
Advantage:
}Without touching source code we can change the query
}Hibernate code will be less polluated with HQL.
Criteria API:
}This is another style
of querying the DB. This is done without directly using either HQL or SQL and
by only using a set of library methods queries are created dynamically and
programmatically
Eg:
Criteria c= session.createCriteria (Employee.class);
Criterion cn =
Restrictions.gt(“salary”, 9000f);
// salary>9000
c.add(cn);
List< Employee>
emps = c.list();
It is useful only for
retrieval.
Example:
1. Criteria cr = session.createCriteria(Employee.class); // To get records having salary more than 2000cr.add(Restrictions.gt("salary", 2000)); // To get records having salary less than 2000cr.add(Restrictions.lt("salary", 2000)); // To get records having fistName starting with zaracr.add(Restrictions.like("firstName", "zara%")); // Case sensitive form of the above restriction.cr.add(Restrictions.ilike("firstName", "zara%")); // To get records having salary in between 1000 and 2000cr.add(Restrictions.between("salary", 1000, 2000)); // To check if the given property is nullcr.add(Restrictions.isNull("salary")); // To check if the given property is not nullcr.add(Restrictions.isNotNull("salary")); // To check if the given property is emptycr.add(Restrictions.isEmpty("salary")); // To check if the given property is not emptycr.add(Restrictions.isNotEmpty("salary"));
2. Criteria cr = session.createCriteria(Employee.class);
Criterion salary = Restrictions.gt("salary", 2000);
Criterion name = Restrictions.ilike("firstNname","zara%");
// To get records matching with OR condistions
LogicalExpression orExp = Restrictions.or(salary, name);
cr.add( orExp );
// To get records matching with AND condistions
LogicalExpression andExp = Restrictions.and(salary, name);
cr.add( andExp );
List results = cr.list();
You
can create AND or OR conditions using LogicalExpression restrictions as
follows:
Persistent object has
4 life cycle states.
}Transient
state ( new state)
Persistent object
is not yet persisted into the database.
}Persisted
/ manages state.
Persistent object
has identify in the database and is associate with persistent.
}Detached
state.
Persistent object has
identify in the database but it is not synchronized with database as it is deassociated with
persistent context.
}Removed /
dead state.
When object state is
removed from DB, it loses identity and it is said to be dead.
Connection Pooling in Hibernate:
There are two kinds
of application
}Standalone
application
}Container
Managed
Standalone
application:
}In this case third
party provide connection pooling software to be usedEg: Apache dbcp, c3po ,
etc.
In hibernate
configuration file
} <property name
=”dialect”>….</property>
}<property name
=”c3po.min_size> 5</property>
}<property name=
“c3po.max_size>50</property>
}<property
name=”c3po.timeout>300</property>
}//sec can
object ideal
}<property
name=”c3po.max_statements”>50</property>
}// max
prepared statement kept in cache
}<property name=”show_sql”>
true</property>
Managed Environment:
}If hibernate is used
in a web application or in an EJB, we instruct hibernate to lookup for the connection
pool (DataSource) and get the pooled
connections.}<property name
=”dialect”>….</property>}<property name=”show_sql”>
true</property>
}Data source is
different for Tomcat & Weblogic
.
Multiple DB’s from Hibernate
Application:
}Develop
one Hibernate configuration file per DB}Create
multiple SessionFactory objects
}Get the
session object from that sessionFactory which represents a
particular DB communication.
}SessionFactory sfOracle= new
Configuration().configure().buildSessionFactory();
}SessionFactory sfSysbase= new
Configuration().configure(“sysbase.cfg.xml”).buildSessionFactory();
Annotations:
Annotations provide
data about a program that is not part of the program itself.
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.
}@Entity
Annotation:
we used the @Entity annotation to the Employee class which marks this class
as an entity bean.
}@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. Its allow you to override the name of the table, its
catalogue, and its schema.
}@Id
Annotations:Each entity bean will
have a primary key, which you annotate on the class with the @Id annotation.
}@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, length , nullable &
unique.
Example:
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() {}
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;
}
}