While using the Hibernate framework, you do not write the code to manage the connection or to deal with statements and result sets. Instead, all the details for accessing a particular data source are configured in the XML files and/or in the Java annotations.
While integrating the Hibernate framework with the Spring Framework, the business objects are configured with the help of the IoC container and can be externalized from the application code. Hibernate objects can be used as Spring beans in your application and you can avail all the benefits of the Spring Framework.
In this section, we will set up the Hibernate environment and create a Spring Hibernate project in STS. The simplest way to integrate Hibernate with Spring is to have a bean for SessionFactory
and make it a singleton and the DAOs classes just get that bean and inject its dependency and get the session from the SessionFactory. The first step in creating a Spring Hibernate project is to integrate Hibernate and connect with the database.
In this chapter, we will use a PostgreSQL database. Please refer to http://www.postgresqltutorial.com/install-postgresql/ to set up a PostgreSQL database server on your machine and download the JDBC driver for the PostgreSQL database; we have used the postgresql-9.3-1102.jdbc3.jar
JDBC connector for PostgreSQL.
We will create a database named ehrpayroll_db
that will contain a table named employee and will populate dummy data to the table. The following is a sample data creation script for a PostgreSQL database.
Let's first create a database for our project in the PostgreSQL database:
ehrpayroll_db
:CREATE DATABASE ehrpayroll_db
EMPLOYEE_INFO
:CREATE TABLE EMPLOYEE_INFO( ID serial NOT NULL Primary key, FIRST_NAME varchar(30) not null, LAST_NAME varchar(30) not null, JOB_TITLE varchar(100) not null, DEPARTMENT varchar(100) not null, SALARY INTEGER );
INSERT INTO EMPLOYEE_INFO (FIRST_NAME, LAST_NAME, JOB_TITLE, DEPARTMENT, SALARY) VALUES ('RAVI', 'SONI', 'AUTHOR', 'TECHNOLOGY', 5000);
The following figure shows the created table with the data inserted:
To integrate Hibernate, we need to perform these steps:
.zip
file for Windows) the latest version of Hibernate from http://www.hibernate.org/downloads. Once you unzip the downloaded ZIP file, the directory structure will appear as shown in the following screenshot:lib
directory, there will be a lot of directories that contain Hibernate-related JARs, as shown in the following screenshot. The required folder contains all the JARs you need to create a basic Java application.Once you have downloaded the Hibernate libraries, you can create a new Spring project and add Hibernate libraries to this project using Java Build Path.
We need to add the JARs required to create our Spring-Hibernate projects. These are shown in the following screenshot:
The Spring Framework lets us define resources such as JDBC DataSource
or Hibernate SessionFactory
as a Spring bean in an application context, which prevents the need for hardcoded resource lookups for application objects. This defined Spring bean references are used by application objects that need to access resources to receive the predefined instances.
The Session
interface in the Hibernate API provides methods to find, save, and delete objects in a relational database. The Hibernate session is created by first creating the SessionFactory
. The Spring Framework provides a number of classes to configure Hibernate SessionFactory
as a Spring bean containing the desired properties.
For session creation, the Spring API provides the implementation of the AbstractSessionFactoryBean
subclass: the LocalSessionFactoryBean
class and the AnnotationSessionFactoryBean
class. Since we will be using annotation style, we will use the AnnotationSessionFactoryBean
class, which supports annotation metadata for mappings. AnnotationSessionFactoryBean
extends the LocalSessionFactoryBean
class, so it has all the basic properties of Hibernate integration.
In the configuration file, we have to declare the sessionFactory
bean and set dataSource
, packagesToScan
or annotatedClasses
, and hibernateProperties
. Let's take a look at these in detail:
dataSource
property sets the name of the data source to be accessed by the underlying application.packagesToScan
property instructs Hibernate to scan the domain object with the ORM annotation under the specified package. The annotatedClasses
property instructs Hibernate to for the ORM-annotated class.hibernateProperties
property sets the configuration details for Hibernate. We have defined only a few important properties out of many configuration parameters that should be provided for every application.The following table describes these properties:
Refer to the Hibernate reference manual for the full list of Hibernate properties at http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/session-configuration.html.
Spring beans, the data source, a SessionFactory
, and a transaction manager bean are configured in the
app-context.xml
file. You should adapt your Hibernate beans according to the project requirements.
Here is an implementation of app-context.xml
. In the following configuration file, we have declared several beans to support the Hibernate SessionFactory
:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation=" http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
In the following code snippet, we have instructed Spring to scan the component under the package org.packt.spring.chapter6.hibernate
using component-scan
:
<context:annotation-config /> <context:component-scan base-package="org.packt.spring.chapter6.hibernate" />
The property-placeholder
will refer to the hibernate.properties
file, as shown in the following code snippet:
<context:property-placeholder location="classpath:/META-INF/spring/hibernate.properties" />
In the following code snippet, the dataSource
bean is declared to provide database connection details to Hibernate:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean>
The sessionFactory
bean is declared in the following code snippet. The Hibernate sessionFactory
bean is the most important part. We have used AnnotationSessionFactoryBean
to support the Hibernate annotation. We have injected the dataSource
bean into sessionFactory
. We have instructed Hibernate to scan for the ORM annotated object. And then we have provided the configuration details for Hibernate using hibernateProperties
, as shown here:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="annotatedClasses" value="org.packt.spring.chapter6.hibernate.model.Employee" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> </props> </property> </bean>
In the following code snippet, we have declared the transactionManager
bean. To access transactional data, SessionFactory
requires a transaction manager. The transaction manager provided by Spring specifically for Hibernate 3 is org.springframework.orm.hibernate3.HibernateTransactionManager
:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
The <tx:annotation-driven>
is declared in the following code snippet to support transaction demarcation requirements using annotations:
<tx:annotation-driven transaction-manager="transactionManager" /> </beans>
The Hibernate- and JDBC-specific properties are stored in a hibernate.properties
file, as follows:
# JDBC Properties jdbc.driverClassName=org.postgresql.Driver jdbc.url=jdbc:postgresql://localhost:5432/ehrpayroll_db jdbc.username=postgres jdbc.password=sa # Hibernate Properties hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect hibernate.show_sql=true
The Java persistent model establishes the static relationships of the persistence model by defining the entity component. The API defines the entity class as the object tier of a table in the database tier. An entity instance is defined as the object tier equivalent of a row in a database table.
The following is a table that maps Object Tier elements to Database Tier elements:
Object Tier element |
Database Tier element |
---|---|
Entity class |
Database table |
Field of entity class |
Database table column |
Entity instance |
Database table row |
Hibernate annotation provides the metadata for object and relational table mapping. This metadata is clubbed into a POJO file that helps users understand the code inside POJO as well as the table structure simultaneously while developing. Hibernate provides JPA implementation, which allows the user to use JPA annotation in model beans. The JPA annotations are explained in the following table:
Now it's time to write Employee.java
. This class will be mapped to the Employee table in the database using Hibernate. The Employee
class fields are annotated with JPA annotations so that we don't need to provide mapping in a separate XML file. It should be noted that Hibernate puts emphasis on overriding the equals()
and hashCode()
methods of a persistent class when used in collections (such as a list or set) because internally Hibernate works with the objects in the session and cache. It is recommended to implement the equals()
and hashCode()
methods using a real-world key, which is a key that would identify the instance in the real world, as shown here:
package org.packt.spring.chapter6.hibernate.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "EMPLOYEE_INFO") public class Employee { @Id @Column(name = "ID") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @Column(name = "JOB_TITLE") private String jobTitle; @Column(name = "DEPARTMENT") private String department; @Column(name = "SALARY") private int salary; // constructor and setter and getter @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Employee)) { return false; } Employee employee = (Employee) obj; if (firstName != null ? !firstName.equals(employee.firstName) : employee.firstName != null) { return false; } else { return true; } } @Override public int hashCode() { return firstName != null ? firstName.hashCode() : 0; } @Override public String toString() { return "Employee [id=" + id + ", name=" + firstName + " " + lastName + ", jobTitle=" + jobTitle + " department=" + department + " salary=" + salary + "]"; } }
In the preceding code snippet:
Employee
class is annotated with the @Entity
annotation, which will define this class as a mapped entity class. The Employee
class is also annotated with the @Table
annotation that defines the table name in the database with which this entity class will map.@ID
annotation, which represents that ID is the primary key of the object. Hibernate will generate the ID value based on the @GeneratedValue
annotation. The GenerationType.IDENTITY
strategy reflects that the ID will be generated by the backend (the ID column of the EMPLOYEE_INFO
table is the primary key with SERIAL
specified, which means the value of ID will be generated and assigned by the database during the insert operation) during insert.@Column
annotation.The Session
interface is an important interface that is required while interacting with a database in Hibernate. The Session
interface is obtained from SessionFactory
. The Session
object is light weight and can be used to attain a physical connection with a database. It is initiated each time an interaction needs to happen with a database. Also, persistent objects are saved and retrieved through a Session
object. It is not usually thread safe, so avoid keeping it open for a long time. They should be created and destroyed as needed. The Session
interface offers create, delete, and read operations for instances of mapped entity classes.
Instances may exist in one of the following three states at a given point in time:
Session
.Session
will be closed.The Session
interface provides a numbers of method such as beginTransaction()
, createCriteria()
, save()
, delete()
, and so on, which you can read about at http://www.tutorialspoint.com/hibernate/hibernate_sessions.htm.
The persistence layer will have the DAO. Let's create DAO classes that will interact with the database using the Hibernate SessionFactory
. The SessionFactory
implementation will be injected into the reference variable at runtime using Spring's Inversion of Control (IoC) feature.
The EmployeeDao
interface declares two methods named getAllEmployees()
and insertEmployee()
, as shown here:
package org.packt.spring.chapter6.hibernate.dao; import java.util.List; import org.packt.spring.chapter6.hibernate.model.Employee; public interface EmployeeDao { // to get all employees public List<Employee> getAllEmployees(); // to insert new employee public void insertEmployee(Employee employee); }
The EmployeeDaoImpl
class is annotated with @Repository
, which indicates that this class is a DAO. It also has the @Transactional(readOnly = true)
annotation, which configures this class and all its methods for read-only access:
package org.packt.spring.chapter6.hibernate.dao; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.packt.spring.chapter6.hibernate.model.Employee; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @Repository @Transactional(readOnly = true) public class EmployeeDaoImpl implements EmployeeDao { @Autowired private SessionFactory sessionFactory; @SuppressWarnings("unchecked") public List<Employee> getAllEmployees() { Session session = sessionFactory.openSession(); String hql = "FROM Employee"; Query query = session.createQuery(hql); List<Employee> emList = query.list(); return emList; } @Transactional(readOnly = false) public void insertEmployee(Employee employee) { Session session = sessionFactory.openSession(); session.save(employee); } }
To get a SessionFactory
, we declare a member variable named sessionFactory
of type SessionFactory
and annotated with the @Autowired
annotation that automatically initializes the SessionFactory
. The next step is to get the session from the sessionFactory
.
In order to use Hibernate in the getAllEmployees()
and insertEmployees()
method, we use a session
object. The session
object is obtained from a SessionFactory
. Using this session
object, we can use the createQuery
method to create queries and run them.
When we are finished with the session, we should close it. We needn't close it by ourselves; the Spring Framework will do this for us.
Let's understand the methods defined in EmployeeDaoImpl
class in more detail:
getAllEmployees()
: The method getAllEmployees()
will fetch all the employee details from the Employee table in the database and return the list of employees.This method will get Hibernate Session
(Session
is the main runtime interface between Java application and Hibernate) from sessionFactory
using the openSession()
method of the SessionFactory
class. This session will use the query
object to call the list()
method that will fetch employees.
insertEmployee()
: The method insertEmployee()
will insert a new record to the Employee table. This method will use the save()
method defined in the Hibernate Session
to perform the INSERT
operation.Annotate this method with @Transactional(readOnly = false)
, which will allow us to perform the INSERT
operation.
We have defined the Service layer, which seems redundant in this demo due to the lack of complexity. This layer will simply take a call from the controller (in Spring MVC) or from the main method and pass this call to the DAOs layer.
The EmployeeService
interface declares two methods named getAllEmployees()
and insertEmployee()
, as shown here:
package org.packt.spring.chapter6.hibernate.service; import java.util.List; import org.packt.spring.chapter6.hibernate.model.Employee; public interface EmployeeService { public List<Employee> getAllEmployees(); public void insertEmployee(Employee employee); }
The EmployeeServiceImpl
class will implement the EmployeeService
interface and provide a definition for the methods declared in the interface. This class has declared a member variable named EmployeeDAO
and annotated it with the @Autowired
annotation. This class is annotated with the @Service
annotation, which makes this class a service class:
package org.packt.spring.chapter6.hibernate.service; import java.util.List; import org.packt.spring.chapter6.hibernate.dao.EmployeeDao; import org.packt.spring.chapter6.hibernate.model.Employee; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeDao employeeDao; public List<Employee> getAllEmployees() { List<Employee> emList = employeeDao.getAllEmployees(); return emList; } public void insertEmployee(Employee employee) { employeeDao.insertEmployee(employee); } }
Once we are done with the preceding configuration, we can write a main method to store values from the Employee
object to the database.
We have created a DBUtils
class annotated with the @Component
annotation to register this class to the Spring container as a bean. This class defined a method named initialize()
and annotated it with the @PostConstruct
annotation.
The @PostConstruct
annotation does not belong to Spring, it's located in the J2EE library: common-annotations.jar
. The @PostConstruct
annotation is a shared annotation that is part of a JSR for basic annotations. It comes with Java SE 6 or newer versions. The commons-annotations.jar
is the final product of the JSR API. The @PostConstruct
annotation defines a method that will be called after a bean has been fully initialized. In other words, it will be called after bean construction and the injection of all dependencies.
The initialize()
method will get the database connection and create a table EMPLOYEE
and insert dummy data to this table. This class has been used in this project to prevent exceptions in case we miss out on creating a table in the database. In a real-world application, we don't need this class:
package org.packt.spring.chapter6.hibernate.util; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import javax.annotation.PostConstruct; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class DBUtils { @Autowired private DataSource dataSource; @PostConstruct public void initialize() { try { Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement(); statement.execute("DROP TABLE IF EXISTS EMPLOYEE_INFO"); statement.executeUpdate("CREATE TABLE EMPLOYEE_INFO(" + "ID serial NOT NULL Primary key, " + "FIRST_NAME varchar(30) not null, " + "LAST_NAME varchar(30) not null, " + "JOB_TITLE varchar(100) not null, " + "DEPARTMENT varchar(100) not null, " + "SALARY INTEGER)"; statement.executeUpdate("INSERT INTO EMPLOYEE_INFO " + "(FIRST_NAME, LAST_NAME, JOB_TITLE, DEPARTMENT, SALARY) " + "VALUES " + "('RAVI', 'SONI', 'AUTHOR', 'TECHNOLOGY', 5000)"; statement.close(); connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }
The SpringHibernateMain
class contains the main method. The ApplicationContext
will initialize the container with the app-context.xml
file we defined:
package org.packt.spring; import org.packt.spring.chapter6.hibernate.model.Employee; import org.packt.spring.chapter6.hibernate.service.EmployeeService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringHibernateMain { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "/META-INF/spring/app-context.xml"); EmployeeService employeeService = context.getBean( "employeeServiceImpl", EmployeeService.class); // insert employee Employee emp = new Employee(); emp.setFirstName("Shree"); emp.setLastName("Kant"); emp.setJobTitle("Software Engineer"); emp.setDepartment("Technology"); emp.setSalary(3000); employeeService.insertEmployee(emp); // fetch all employee for (Employee employee : employeeService.getAllEmployees()) System.out.println(employee); } }
Once you run the application, the following output will be expected:
Hibernate: insert into EMPLOYEE_INFO (DEPARTMENT, FIRST_NAME, JOB_TITLE, LAST_NAME, SALARY) values (?, ?, ?, ?, ?) Hibernate: select employee0_.ID as ID0_, employee0_.DEPARTMENT as DEPARTMENT0_, employee0_.FIRST_NAME as FIRST3_0_, employee0_.JOB_TITLE as JOB4_0_, employee0_.LAST_NAME as LAST5_0_, employee0_.SALARY as SALARY0_ from EMPLOYEE_INFO employee0_ Employee [id=1, name=RAVI SONI, jobTitle=AUTHOR department=TECHNOLOGY salary=5000] Employee [id=2, name=Shree Kant, jobTitle=Software Engineer department=Technology salary=3000]
Once the application has been run successfully, the updated Employee table with all the data will be as shown here:
In the previous sections, we discussed mapping persistent objects using Hibernate. In the next section, we will understand HQL. Hibernate is engineered around the object model and provides a powerful query language named HQL to define our queries so we don't need to construct SQL to interact with the database. HQL is similar to SQL except that we will use objects instead of table names.
3.146.255.7