「Spring」 Hibernate と連携してみる ( Spring 3 系 + Hibernate 3 系 )

Spring ( 3.2.12 ) と Hibernate ( 3.6.10 ) を連携してみたので、メモしておきます。

使うパッケージは org.springframework.orm.hibernate3 になるみたいです。

・org.springframework.orm.hibernate3 (Spring Framework 3.2.13.RELEASE API)
http://docs.spring.io/spring/docs/3.2.13.RELEASE/javadoc-api/org/springframework/orm/hibernate3/package-summary.html

ドキュメントは以下あたりに。

・15. Object Relational Mapping (ORM) Data Access
http://docs.spring.io/spring/docs/3.2.13.RELEASE/spring-framework-reference/html/orm.html#orm-hibernate


1. DAO クラスを作成する

■ PersonDAO.java

package com.example.hibernate;

import java.util.List;

public interface PersonDAO {
	public List<Person> getAllPerson();
	public void addPerson(Person p);
}

■ PersonDAOImpl.java

package com.example.hibernate;

import java.util.List;

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

@Component
public class PersonDAOImpl implements PersonDAO {

	@Autowired
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	@Override
	public List<Person> getAllPerson() {
		List<Person> persons = sessionFactory.getCurrentSession().createCriteria(Person.class).list();
		return persons;
	}
	
	@Override
	public void addPerson(Person p) {
		sessionFactory.getCurrentSession().persist(p);	
	}

	protected Session openSession() {
		return sessionFactory.openSession();
	}

}

@Autowired で SessionFactory オブジェクトされるようにしています。
設定は後述しますが、LocalSessionFactoryBean を Bean 定義ファイルに記述することで Hibernate の SessionFactory を生成してくれるみたいです。

・LocalSessionFactoryBean (Spring Framework 3.2.13.RELEASE API)
http://docs.spring.io/spring/docs/3.2.13.RELEASE/javadoc-api/org/springframework/orm/hibernate3/LocalSessionFactoryBean.html


2. サービスクラスを作成する

■ PersonService.java

package com.example.hibernate;

import java.util.List;

public interface PersonService {
	public List<Person> getAllPerson();
	public void addPerson(Person p);
}

■ PersonServiceImpl.java

package com.example.hibernate;

import java.util.List;

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

@Component
public class PersonServiceImpl implements PersonService {

	@Autowired
	PersonDAO dao;

	@Override
	@Transactional(readOnly = true)
	public List<Person> getAllPerson() {
		return dao.getAllPerson();
	}

	@Override
	@Transactional
	public void addPerson(Person p) {
		dao.addPerson(p);
	}
}


3. Bean 定義ファイルを作成する

hibernate.xml

<?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:aop="http://www.springframework.org/schema/aop"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

  <context:property-placeholder location="classpath:jdbc.properties"/>
  <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
  </bean>
  
  <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource"/>
    <property name="mappingResources">
      <list>
        <value>com/example/hibernate/Person.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
        <prop key="hibernate.show_sql">true</prop>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
      </props>
    </property>
  </bean>
  
  <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="mySessionFactory"/>
  </bean>

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

  <context:annotation-config />
  <context:component-scan base-package="com.example.hibernate" />

</beans>

Hibernate との連携の固有の設定は、LocalSessionFactoryBean、HibernateTransactionManager あたりですかね。
ドキュメントではトランザクションインタセプタの設定を Bean 定義ファイルで行なっていますが、面倒なので上記ではアノテーション使ってやるようにしています。


4. Main クラスを作成する

■ Main.java

package com.example.hibernate;

import java.util.List;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

public class Main {

	public static void main(String[] args) {
		new Main().test();
	}

	public void test() {
		try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("hibernate.xml")) {
			
			PersonService ps = context.getBean(PersonService.class);

			Person p = new Person();
			p.setId(3);
			p.setName("oro");
			ps.addPerson(p);
			
			List<Person> persons = ps.getAllPerson();
			for (Person person : persons) {
				System.out.println(person.getId() + ":" + person.getName());
			}
		}
	}
}

作成するものは、上記で以上です。

log4j の設定ファイルで、HibernateTransactionManager のデバッグログを有効にしてやると ( *1 )、以下のようなログが出力されるはずです。ひとまずちゃんと動いてそうかな。

2015-03-24 00:59:43,350  INFO HibernateTransactionManager - Using DataSource [org.apache.commons.dbcp.BasicDataSource@66328ec4] of Hibernate SessionFactory for HibernateTransactionManager
2015-03-24 00:59:43,383 DEBUG HibernateTransactionManager - Creating new transaction with name [com.example.hibernate.PersonServiceImpl.addPerson]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2015-03-24 00:59:43,404 DEBUG HibernateTransactionManager - Opened new Session [org.hibernate.impl.SessionImpl@656ebb9] for Hibernate transaction
2015-03-24 00:59:43,405 DEBUG HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@656ebb9]
2015-03-24 00:59:43,415 DEBUG HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [jdbc:postgresql://127.0.0.1:5432/testdb, UserName=*****, PostgreSQL Native Driver]
2015-03-24 00:59:43,424 DEBUG HibernateTransactionManager - Initiating transaction commit
2015-03-24 00:59:43,424 DEBUG HibernateTransactionManager - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@656ebb9]
Hibernate: insert into T1 (name, id) values (?, ?)
2015-03-24 00:59:43,459 DEBUG HibernateTransactionManager - Closing Hibernate Session [org.hibernate.impl.SessionImpl@656ebb9] after transaction
2015-03-24 00:59:43,460 DEBUG HibernateTransactionManager - Creating new transaction with name [com.example.hibernate.PersonServiceImpl.getAllPerson]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
2015-03-24 00:59:43,460 DEBUG HibernateTransactionManager - Opened new Session [org.hibernate.impl.SessionImpl@3872dcd8] for Hibernate transaction
2015-03-24 00:59:43,460 DEBUG HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@3872dcd8]
2015-03-24 00:59:43,461 DEBUG HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [jdbc:postgresql://127.0.0.1:5432/testdb, UserName=*****, PostgreSQL Native Driver]
Hibernate: select this_.id as id0_0_, this_.name as name0_0_ from T1 this_
2015-03-24 00:59:43,471 DEBUG HibernateTransactionManager - Initiating transaction commit
2015-03-24 00:59:43,471 DEBUG HibernateTransactionManager - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@3872dcd8]
2015-03-24 00:59:43,472 DEBUG HibernateTransactionManager - Closing Hibernate Session [org.hibernate.impl.SessionImpl@3872dcd8] after transaction
1:hoge
2:uga
3:oro

( *1 )

log4j.appender.stderr=org.apache.log4j.ConsoleAppender
log4j.appender.stderr.Target=System.err
log4j.appender.stderr.layout=org.apache.log4j.PatternLayout
log4j.appender.stderr.layout.ConversionPattern=%d %5p %c{1} - %m%n

log4j.logger.org.springframework.orm.hibernate3.HibernateTransactionManager=DEBUG,stderr


だいぶかけ足でしたが、以上です。

[ 環境情報 ]
Windows 7 SP1
Java SE 7 Update 51
Spring Framework 3.2.13
Hibernate 3.6.10.Final
PostgreSQL 9.0.4
PostgreSQL JDBC Driver 9.0-801