Saturday, 5 November 2016

4. Hibernate Use of Spring's HibernateTransactionManager

In previous Hibernate tutorials, we covered basics of Hibernate Spring integration however we also saw for every transaction, we have to open session using method SessionFactory.openSession() then begin transaction, perform operation and then either commit or rollback transaction. This makes it transaction handling manual and not very convenient, not so readable and cumbersome as well.

HibernateTransactionManager handles transaction manager in Spring. The application that uses single hibernate session factory for database transaction, has good choice to use HibernateTransactionManager. SessionFactory.getCurrentSession() is required for Hibernate access code that needs to support this transaction handling mechanism, with the SessionFactory being configured with SpringSessionContext.

In this tutorial, we will update previous tutorial to use HibernateTransactionManager.

In Spring bean configuration file spring.xml, add bean definition for 'transactionManager' for class 'org.springframework.orm.hibernate4.HibernateTransactionManager'

spring.xml
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?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:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
  http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">

 <context:component-scan base-package="in.blogspot.ashish4java.employeesystem" />

 <tx:annotation-driven />

 <context:property-placeholder location="classpath:hibernate.properties" />

 <bean id="myDataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="${jdbc.driverClassName}" />
  <property name="url" value="${jdbc.url}" />
  <property name="username" value="${jdbc.user}" />
  <property name="password" value="${jdbc.pass}" />
 </bean>

 <bean id="sessionFactory"
  class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  <property name="packagesToScan" value="in.blogspot.ashish4java.employeesystem.model"></property>
  <property name="dataSource" ref="myDataSource" />
  <property name="hibernateProperties">
   <props>
    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
    <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
    <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
    <prop key="current_session_context_class">${hibernate.current_session_context_class}</prop>
    <prop key="cache.provider_class">${hibernate.cache.provider_class}</prop>
    <prop key="hibernate.autocommit">${hibernate.autocommit}</prop>
    <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
   </props>
  </property>
 </bean>

 <bean id="transactionManager"
  class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
 </bean>

</beans>

The default value for the transaction-manager attribute in  is 'transactionManager'. So we have kept bean id as 'transactionManager' for class 'org.springframework.orm.hibernate4.HibernateTransactionManager'

Once this is done, let's modify DAO classes first to get rid of all boilerplate code related to transaction.

AbstractDao.java
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package in.blogspot.ashish4java.employeesystem.dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class AbstractDao {

 @Autowired
 SessionFactory sessionFactory;

 protected Session getsession() {
  return sessionFactory.getCurrentSession();
 }

 public void createEntity(Object entity) {
  getsession().save(entity);
 }

 public void updateEntity(Object entity) {
  getsession().update(entity);
 }

 public void deleteEntity(Object entity) {
  getsession().delete(entity);
 }

}

Here, we are getting current(same) session associated that thread as property hibernate.current_session_context_class is set to thread. We have also removed code related to begin transaction and committing/rolling back transaction. Spring's transaction manager takes care of that.

Updated EmployeeDaoImpl.java is as below,

EmployeeDaoImpl.java
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package in.blogspot.ashish4java.employeesystem.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import in.blogspot.ashish4java.employeesystem.model.Employee;

@Repository
public class EmployeeDaoImpl extends AbstractDao implements EmployeeDao {

 @Override
 public void createEmployee(Employee emp) {
  createEntity(emp);
 }

 @Override
 public void updateEmployee(Employee emp) {
  updateEntity(emp);
 }

 @Override
 public void deleteEmployee(Employee emp) {
  deleteEntity(emp);
 }

 @Override
 public Employee getEmployee(int employeeId) {
  Session session = getsession();
  Criteria criteria = session.createCriteria(Employee.class).add(Restrictions.eq("employeeId", employeeId));
  return (Employee) criteria.uniqueResult();
 }

 @SuppressWarnings("unchecked")
 @Override
 public List<Employee> findAllEmployees() {
  Session session = getsession();
  Criteria criteria = session.createCriteria(Employee.class);
  return (List<Employee>) criteria.list();
 }

 @SuppressWarnings("unchecked")
 @Override
 public List<Employee> findAllEmployeesByDesignation(String designation) {
  Session session = getsession();
  Query query = session.createQuery("from Employee where designation = :designation");
  query.setString("designation", designation);
  return query.list();
 }

}

We also need to annotate Service class or its method that they are transactional as below. 

EmployeeServiceImpl.java

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package in.blogspot.ashish4java.employeesystem.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import in.blogspot.ashish4java.employeesystem.dao.EmployeeDao;
import in.blogspot.ashish4java.employeesystem.model.Employee;

@Service ("empService")
@Transactional
public class EmployeeServiceImpl implements EmployeeService {

 @Autowired
 EmployeeDao employeeDao;

 @Override
 public void createEmployee(Employee emp) {
  employeeDao.createEmployee(emp);

 }

 @Override
 public void updateEmployee(Employee emp) {
  employeeDao.updateEmployee(emp);
 }

 @Override
 public void deleteEmployee(Employee emp) {
  employeeDao.deleteEmployee(emp);
 }

 @Override
 public Employee getEmployee(int employeeId) {
  return employeeDao.getEmployee(employeeId);
 }

 @Override
 public List<Employee> findAllEmployees() {
  return employeeDao.findAllEmployees();
 }

 @Override
 public List<Employee> findAllEmployeesByDesignation(String designation) {
  return employeeDao.findAllEmployeesByDesignation(designation);
 }

}

Once all these changes are done, run MainClient class and you will see no difference in outcome.

No comments:

Post a Comment