Spring ORM

Introduction

Spring provides a convenient way to integrate object relational persistence frameworks such as Hibernate, JPA, and JDO for data access object, transaction and resource management implementation. Spring supports ORM integration with generic transaction features and DAO exception hierarchy.

Advantage of Spring ORM

  • Easier testing: Spring’s IoC approach makes it easy to swap the implementations and configuration locations of Hibernate SessionFactory instances, JDBC DataSource instances, transaction managers, and mapped object implementations (if needed). This in turn makes it much easier to test each piece of persistence-related code in isolation.

  • Common data access exceptions: Spring can wrap exceptions from your ORM tool, converting them to a common runtime DataAccessException hierarchy.

  • General resource management: Spring application contexts can handle the location and configuration of Hibernate SessionFactory instances, JPA EntityManagerFactory instances, JDBC DataSource instances, and other related resources. This makes these values easy to manage and change.

  • Integrated transaction management: You can wrap your ORM code with a declarative, aspect-oriented programming (AOP) style method interceptor either through the @Transactional annotation or by explicitly configuring the transaction AOP advice in an XML configuration file.

Hibernate Integration

Hibernate objects can be defined in Spring container as a bean and injected in DAO objects.

Session Factory Setup

Spring container is the factory of all kinds of objects. Hibernate SessionFactory can be defined in Spring IOC container as a bean. Here is XML application context definition that shows how to set up a JDBC Datasource and a Hibernate SessionFactory.

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

<property name="driverClassName" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql://localhost:3306/ST_JAVA" />

<property name="username" value="root" />

<property name="password" value="" />

</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">

org.hibernate.dialect.MySQLDialect

</prop>

<prop key="hibernate.show_sql">true</prop>

<prop key="hibernate.hbm2ddl.auto">update</prop>

</props>

</property>

<property name="mappingResources">

<list>

<value>in/co/sunrays/dto/Account.hbm.xml</value>

<value>in/co/sunrays/dto/User.hbm.xml</value>

</list>

</property>

</bean>

Plain Hibernate 3 API DAO Implementation

Hibernate 3 has a feature called contextual sessions. Hibernate itself manages one current Session per transaction in contextual sessions. This is roughly equivalent to Spring’s synchronization of one Hibernate Session per transaction. This approach is recommended to develop DAO classes in Hibernate.

Here is the DAO implementation example using plain Hibernate 3 API:

@Repository

public class CollegeDAOHibImpl implements CollegeDAOInt {

@Autowired

private SessionFactory sessionFactory;

public long add(College dto) {

Session session = sessionFactory.getCurrentSession();

session.save(dto);

return dto.getId();

}

public long update(College dto) {

Session session = sessionFactory.getCurrentSession();

session.update(dto);

return dto.getId();

}

Make following entry in applicationContext.xml

<context:component-scan base-package="com.sunilos.annotation" />

Service Class

Service class contains business logic. It is defined by @Service annotation. It does transaction handling with help of Spring AOP.

There are two ways to apply transactions:

  • XML Configuration

  • @Transactional annotation

XML Configuration

Here is sample code of UserService and its respective configuration setting in applicationContext.xml.

public class UserServiceImpl implements UserServiceInt {

private UserDAOInt dao = null;

private static Logger log = Logger.getLogger(UserServiceImpl.class);

public long add(UserDTO dto) {

long pk = dao.add(dto);

return pk;

}

applicationContext.xml configuration

<bean id="userService" class="com.sunilos.service.UserServiceImpl"

autowire="byType" />

<!-- Hibernate Transaction Manager -->

<bean id="hibTransactionManager"

class="org.springframework.orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory" />

</bean>

<!-- Configure Declarative Transaction on Service classes using Spring AOP -->

<!-- The transactional advice contains methods and attribute mapping for

Hibernate Transaction Manager -->

<tx:advice id="hibTxAdvice" transaction-manager="hibTransactionManager">

<tx:attributes>

<!-- all methods starting with 'find' and 'search' are read-only -->

<tx:method name="find*" read-only="true" />

<tx:method name="search*" read-only="true" />

<!-- other methods use the default transaction settings -->

<tx:method name="*" propagation="REQUIRED" />

</tx:attributes>

</tx:advice>

<!-- ensure that the above transactional advice runs for any execution of

an operation defined by the *ServiceImpl* classes -->

<aop:config>

<aop:pointcut id="serviceOperations"

expression="execution(* com.sunilos.service.*ServiceImpl.*(..))" />

<aop:advisor advice-ref="hibTxAdvice" pointcut-ref="serviceOperations" />

</aop:config>

Annotation @Transactional

Here is sample beans College and its applicationContext.xml configuration that applies annotation based transaction.

@Service(value = "collegeService")

public class CollegeServiceImpl implements CollegeServiceInt {

@Autowired

private CollegeDAOInt dao = null;

@Transactional(readOnly = true)

public College get(long id) {

return dao.findByPK(id);

}

@Transactional(propagation = Propagation.REQUIRED)

public long add(College dto) {

long id = dao.add(dto);

return id;

}

applicationContext.xml configuration

<!--Scan @Repository, @Service, @Component and @Controller spring beans -->

<context:component-scan base-package="com.sunilos.annotation" />

<!-- enable the configuration of transactional behavior based on annotations -->

<tx:annotation-driven transaction-manager="hibTransactionManager" />

Test case

UserServiceTestase

CollegeServiceTestcase

AccountServiceTestcase

Maven Dependency

<!-- Hibernate O/RM implementation of the JPA specification -->

<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate-entitymanager</artifactId>

<version>3.5.0-Final</version>

</dependency>

<!-- Hibernate is depends on slf4j-api and hibernate-entitymanager -->

<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate-core</artifactId>

<version>3.5.0-Final</version>

</dependency>

FAQ

Q: What are the differences between session.getCurrentSession() and session.openSession()?

A: openSession method will always open a new session whereas getCurrentSession will get the current session if already exist or create new session.