Hibernate
Hibernate
1. What is Hibernate? – In our Java application, we deal with the database using JDBC i.e we create
our own queries & execute them. Hibernate simplifies this process as it creates it’s own queries
& fires them. Hibernate will already be having the DAO classes. Hibernate internally uses the
JDBC steps only.
Also, ORM(Object Relational Mapping) means, in our Java application we will be having multiple
classes whose POJOs we will create(Object). We will also be having a Relational
Database(Relational) like MySQL. Now each POJO class will be mapped(Mapping) to a table in
the database & each field of the POJO class will be mapped to a column of that table in the
database. This is the concept of Object Relational Mapping.
Now at the time of creating a POJO class itself, we will tell hibernate(using XML or annotation)
that this class is mapped to which table and each field of this class will be mapped to which
column of that table.
2. Now to create a Hibernate project, we will create a new Maven project and select the following
archetype-
In pom.xml we need to add these dependencies for a hibernate project.
Now suppose if we want to go ahead with a simple Java project instead of a Maven project, then
we create a new simple Java project and add all required jars manually to the project. To add
the jars, search “Hibernate jars” on Google and go to the search result with hibernate.org link ->
Click on “Latest Stable” on top-right -> Click on “Download ZIP archive” on the right hand side of
the page. Then a zip file be downloaded, unzip it, in the unzipped folder -> lib -> required -> add
all the jars to your project buildpath(classpath). Do the same for mysql-connector jar.
Now this is our configuration file for hibernate. The standard name of this file should be
hibernate.cfg.xml If we give any other name then we have to explicitly mention the path of this
file in the main() method. In this configuration file, we are setting the driver class, url, username
& pw of the database with which we are connecting our java application.
For MySQL database, dialect is MySQLDialect which is a class.
hbm2ddl.auto is “update” which means that table will be created only once & records will be
added into that table. If the hbm2ddl.auto is “create” then every time the table will be dropped
and a new one will be created.
show_sql is true so the queries that are executed will be displayed on the console.
<mapping> tag is to declare the class with @Entity annotation
3.
@Table can be used to change the table name i.e if we don’t want the table name to be same as
class name
@Transient when used above a field, that field will not be saved as a column in the table in db
@Column(length=100) if written above a field means that the max length of that attribute in the
table will be 100 i.e varchar(100)
@GeneratedValue(strategy = GenerationType.IDENTITY) above a field means that attribute will
be auto incremented.
We have get() & load() hibernate methods to fetch the data. Both the methods belong to
Session & have same syntax & functionality except a few differences, as mentioned above.
Now the 1st & 3rd point are clear i.e if we are fetching a record from the db that does not exist
then get() will return null but load() will throw an ObjectNotFoundException. Thus, get() should
be used if we are not sure if the record to be fetched exists in the db or not, and load() should
be used if we are sure if the record to be fetched exists in db.
Now in the 2nd point, when we do a get() call for a record, the select query will be executed and
the returned object will be stored in Session object. Now if we do a get() call for the same
record, then hibernate will first check the Session object to see if an object for the asked record
exists or not. If it exists then it will return that object, else if it does not exist then hibernate will
fire up the select query & hit the database.
But in case of load(), when we do a load() call, then hibernate will return a proxy object which
we will store in some variable(let’s say Student st). Now hibernate hasn’t fired any select query
& hit the database, it has just returned a proxy object. When we will actually use this st
object(like printing st or getting the name of this st object), only then hibernate will fire a select
query and hit the database. So unless the data is actually needed in some way, hibernate won’t
hit the database.
Here, we are just doing a load() call and storing the returned object into student & student1
variables. But we are not using these variables. So in the console we can see that the select
query was never fired & database was never hit.
Now here we are actually using the student object to print the name of the student and thus
this time the select query was fired and database was hit & name was printed.
class Address{
String houseNo;
String street;
String city;
}
Now when hibernate will create table of Student, it will encounter a field add of type Address.
Now we have not mentioned @Entity annotation above Address class so hibernate does not
know yet what Address is. What we want is that houseNo, street and city columns should be
added in the Student table. So the Student table should look like-
id name houseNo street city
@Embeddable
class Address{
String houseNo;
String street;
String city;
}
@Entity
class Question{
@Id
int queId; //queId is the primary key of Question table
String question;
Answer ans; //where Answer is another class
}
@Entity
class Answer{
@Id
int ansId; //ansId is the primary key of Answer table
String answer;
}
Here, we want that ansId should be foreign key in the Question table i.e each question of
Question table must be mapped to it’s corresponding answer in Answer table through ansId
attribute.
So to achieve this, we will just mention @OneToOne annotation above the Answer ans field and
hibernate will know that ansId of Answer table is foreign key in Question table.
@Entity
class Question{
@Id
int queId; //queId is the primary key of Question table
String question;
@OneToOne
Answer ans; //where Answer is another class
}
@Entity
class Answer{
@Id
int ansId; //ansId is the primary key of Answer table
String answer;
}
7. @OneToMany annotation – Now in the above example, if we want to have multiple answers for
one question, we need to have a List<Answer> answers; field in the Question class & need to
use @OneToMany annotation above this field, thus hibernate will know that the ansId will be
the multi valued foreign key in Question table.
@Entity
class Question{
@Id
int queId; //queId is the primary key of Question table
String question;
@OneToMany
List<Answer> answers; //where Answer is another class
}
@Entity
class Answer{
@Id
int ansId; //ansId is the primary key of Answer table
String answer;
}
Note – Make sure to add the @Entity class in hibernate.cfg.xml using <mapping> tag.
@JoinTable annotation is to change the name of the table formed due to @ManyToMany
annotation.
Inside @JoinTable annotation we are using joinColumns to change the name for the first column
of the resultant table & inverseJoinColumns to change the name for the second column of the
resultant table.
@Entity
class Answer{
@Id
int ansId; //ansId is the primary key of Answer table
String answer;
}
10. Hibernate Object states – A Pojo object that we create has four states in it’s lifecycle. These
states are-
i. Transient State – When the object is just created & values are filled, then the object is said to
be in Transient state. In this state the object neither exists in database nor in Session object. It
just exists on the memory.
ii. Persistent State – When we save the object in session using session.save(obj); then the object
gets stored in database as a record, as well as in the Session object. Now the Pojo object is
associated to the record in the db & the Session object so any change we make to the Pojo
object will be reflected to the record in db & the object in Session object.
iii. Detached State – If we clear the session or close the session by doing session.clear() or
session.close() then the object moves to Detached state. In this state, it is no longer associated
with the database & the Session object, so the object no longer exists in the Session object & is
no longer associated with the record in database. So any change we make in the values of this
object now wouldn’t reflect in the record in the db, the record would still have old values.
iv. Removed State – If we delete the object from the session by doing session.delete(obj); then
the object will remain in the Session object but will be removed from the database. So the
record will be deleted from the db.
Now here we have a normal Student object. Initially for this Student object, id=1414,
name=”Peter”, city=”ABC”, certi.name=”Java Hibernate Course” & certi.duration=”2 months”.
Then in 38th line we are changing the name to “John”. So if we run the above program, then in
the database the record will be inserted with name=”John” and not “Peter” coz the Student
object is in Persistent state at line 38th and thus any change made in the object will be
reflected in the db as well.
Now in 44th line we are again changing the name of the object to “Sachin” but before this line
we have already closed the session. So the object is in Detached state and thus any change in
Student object won’t be reflected in the database and thus the record will still have “John” as
the name.
11. HQL(Hibernate Query Language) – We saw that using get() or load() we can fetch a record from
any table by giving the id(primary key). But what if we want to execute a complex query like
“select * from Student where sname=’John’;“ So to execute complex queries(could involve
multiple tables as well like using joins etc), we have HQL.
Entity name means Class name. In HQL we would write the class name & the fields of the class in
the query. Eg: If we want to get all details of John-
In HQL: from Student where studentName = ‘John’; //here studentName is the field of Student
class.
In SQL: Select * from student_details where sName = ‘John’; //here student_details is the table
& sName is the column name.
Fetching record-
HQLExample.java to demonstrate use of HQL. The HQL query would just have “from Student” to
return all the records in the Student table. Note that here Student is the class name & not the
table name. In 22nd line we are creating the query by using a Query object(org.hibernate). Now if
our query returns just a single record then we will get the result using q.uniqueResult(); as in
26th line and store it in a Student object.
But if our query returns multiple records then we will get the result using q.list() and store the
result in a list of Student like List<Student> as in 30th line. We can also modify the HQL query
with where, and etc clauses. Note that the “city” in the where clause in the above example is the
field of Student class and not the column name. Also, we have hardcoded the city as ‘Lucknow’
in the above example.If we want to dynamically set the value i.e from a variable, then we can do
like-
Here, in the query itself, we have used a variable x(can use any variable) with a : (colon). Now
we can set any value in place of this x(This is the signature i.e colon then the variable name). To
set the value we use q.setParameter(“variable_name”,”value”) as in 28th line. Here we have
hardcoded the value “Lucknow” but the value can be a variable too. Similarly, we can also have
multiple variables in the query which can be replaced by multiple values.
The query will change for deleting record/s from the table. Student is the class name here & city
is the field of Student class. We are using alias of Student as s like we normally do in SQL. Since
it’s a write operation on the database, we need to begin & commit the transaction as in 41st &
47th line. We fire a delete query using executeUpdate() as in 44th line.
In 61st line we can either use q3.list(); or q3.getResultList(); Here in the query in 59th line,
question, questionId and answers(List<Answer> answers)are fields of Question class. We have
declared q.answers as a & then printing a.answer so hibernate will print the corresponding
answers for each question as we are using INNER JOIN.
Now, in the above examples we can see that Query & q.setParameter are deprecated. This is coz
org.hibernate.Query is deprecated since Hibernate 5.2 To resolve this issue, we can use
org.hibernate.query.Query after Hibernate 5.2 instead of just org.hibernate.Query
12. Pagination using HQL – Let’ say we have hundreds of rows in a table in our DB. Now when we
fetch some data from this table, we want the returned data to start from a certain number of
row and we also want only a certain number of rows to be returned. This is called Pagination.
Eg: If we have 50 rows overall, we want 7 rows to be returned starting from row number 15 so
row number 15, 16, 17, 18, 19, 20 and 21 will be returned & displayed. Here, to set the number
7 i.e the number of rows returned we use query.setMaxResults(7); and to set the starting index
i.e 15, we use query.setFirstResult(15);