SpringとHibernateの連携 - データアクセス処理の作成

Daoインターフェース作成

Hibernate Synchronizerで生成されたEmployeeDAOインターフェースを次の内容で修正。

package sample.test.dao.iface;

import java.util.List;
import org.springframework.dao.DataAccessException;

import sample.test.Employee;

public interface EmployeeDAO {
	// 従業員IDから情報を参照
	public Employee get(String id) throws DataAccessException;

	// 全従業員情報を参照
	public List<Employee> findAll() throws DataAccessException;

	// 従業員情報を登録
	public String save(Employee employee) throws DataAccessException;

	// 従業員情報を更新
	public void update(Employee employee) throws DataAccessException;

	// 従業員情報を削除
	public void delete(String id) throws DataAccessException;
}

Dao実装クラス作成

上記インターフェースの実装クラスEmployeeDAOImplを作成。これはHibernate Synchronizerで生成されたものは使えないので、新たに作成。ポイントは次のとおり。

  • Hibernateを使用するためorg.springframework.orm.hibernate3.support.HibernateDaoSupport抽象クラスを継承する。
  • データベースにアクセスするためにorg.springframework.orm.hibernate3.HibernateTemplateクラスのメソッドを使用する。このクラスは内部でHibernateのSessionクラスを使用している。
  • 従業員IDから情報を参照するときは、HibernateTemplateクラスのload()メソッドを使用する。get()メソッドでも参照できるがload()メソッドは情報が存在しない場合に例外をスローする。
  • 削除処理は従業員IDのみ渡して行いたいので、HibernateTemplateの削除メソッドの中でget(id)を呼び出す。

ソースの内容は次の内容になる。

package sample.test.dao;

import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.dao.DataAccessException;

import sample.test.dao.iface.*;
impo</span>rt sample.test.Employee;

public class EmployeeDAOImpl extends HibernateDaoSupport implements EmployeeDAO{
	// 従業員IDから情報を参照
	public Employee get(String id) throws DataAccessException{
		Employee employee 
        = (Employee) getHibernateTemplate().load(Employee.class, id);
		   return employee;
    }
 
	// 全従業員情報を参照
	public List<Employee> findAll() throws DataAccessException{
        return getHibernateTemplate().loadAll(Employee.class);
    }
	// 従業員情報を登録
	public void save(Employee employee) throws DataAccessException {
		getHibernateTemplate().save(employee);
}
	// 従業員情報を更新
	public void update(Employee employee) throws DataAccessException {
		getHibernateTemplate().update(employee);
	}

	// 従業員情報を削除
	public void delete(String id) throws DataAccessException {
		getHibernateTemplate().delete(get(id));
	}
}

Dao実装クラスのBean定義

次の内容を/WEB-INF/applicationContext.xml に追加する。EmployeeDAOImplクラスが継承しているHibernateDaoSupport抽象クラスにはSessionFactory型のフィールドが定義されている。

  <bean id="employeeDao" class="sample.test.dao.EmployeeDAOImpl">
    <property name="sessionFactory"><ref local="sessionFactory"/></property>
  </bean>

テストケースの作成

  1. プロジェクトのプロパティ画面でJavaのビルドパスJUnitライブラリを追加する。ライブラリーのタブをクリックし、「ライブラリー追加」ボタンを押してJUnitを選択する。
  2. ソースフォルダーを右クリック、新規→作成を選択、ウィザード選択でJava配下のJUnitテスト・ケースを選択する。
  3. JUnitテストケース画面で名前とテスト元クラスを入力して「次へ」ボタンを押す。
  4. テスト・メソッド画面でテストを行うEmployeeImplクラスのメソッドをチェックし、「終了」ボタンを押すとテストケースの雛形が作成される。
  5. 雛形を次の内容で修正し、JUnitでテストを実行する。この際、実行時のクラスパスにプロジェクト配下の「WebContent」を追加する必要がある。
package sample.test.dao;

import sample.test.*;
import sample.test.dao.iface.*;
import java.text.SimpleDateFormat;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;

public class EmployeeDAOImplTest extends TestCase {
	private EmployeeDAO dao = null;

	protected void setUp() throws Exception {
		super.setUp();
		ApplicationContext ctx = new ClassPathXmlApplicationContext(
				"/WEB-INF/applicationContext.xml");
		dao = (EmployeeDAO) ctx.getBean("employeeDao");
	}

	public void testSave() throws Exception {
		Employee employee = new Employee();
		employee.setId("12345");
		employee.setPassword("56789");
		employee.setFirstName("テスト");
		employee.setLastName("太郎");
		employee.setFirstKananame("てすと");
		employee.setLastKananame("たろう");
		employee.setEmail("sample@sample.test.com");
		employee.setPhoneNumber("999-9999");

		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String date = "20071219";
		employee.setBirthDate(sdf.parse(date));

		dao.save(employee);

		Employee newEmployee = dao.get("12345");

		assertEquals("12345", newEmployee.getId());
	}

	public void testUpdate() throws Exception {
		Employee employee = new Employee();
		employee.setId("12345");
		employee.setPassword("56789");
		employee.setFirstName("テスト");
		employee.setLastName("次郎");
		employee.setFirstKananame("てすと");
		employee.setLastKananame("たろう");
		employee.setEmail("sample@sample.test.com");
		employee.setPhoneNumber("999-9999");

		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String date = "20071219";
		employee.setBirthDate(sdf.parse(date));

		dao.update(employee);

		Employee newEmployee = dao.get("12345");

		assertEquals("次郎", newEmployee.getLastName());
	}

	public void testGet() throws Exception {
		Employee employee = dao.get("12345");
		assertEquals("テスト", employee.getFirstName());
		assertEquals("次郎", employee.getLastName());
		assertEquals("てすと", employee.getFirstKananame());
		assertEquals("たろう", employee.getLastKananame());
		assertEquals("sample@sample.test.com", employee.getEmail());
		assertEquals("999-9999", employee.getPhoneNumber());
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
		assertEquals("2007/12/19", sdf.format(employee.getBirthDate()));
	}

	public void testFindAll() throws Exception {
		List<Employee> employeeList;
		int count = 0;
		employeeList = dao.findAll();
		count = employeeList.size();

		Employee employee = new Employee();
		employee.setId("010101");
		employee.setPassword("56789");
		employee.setFirstName("テスト");
		employee.setLastName("次郎");
		employee.setFirstKananame("てすと");
		employee.setLastKananame("じろう");
		employee.setEmail("tesi2@email");
		employee.setPhoneNumber("888-8888");

		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String date = "20071215";
		employee.setBirthDate(sdf.parse(date));

		dao.save(employee);
		employeeList = dao.findAll();
		assertEquals("総件数", count + 1, employeeList.size());
	}

	public void testDelete() throws Exception {
		dao.delete("12345");
		dao.delete("010101");

		try {
			dao.get("12345");
			dao.get("010101");
			fail("Employee found in database");
		} catch (DataAccessException dae) {
			assertNotNull(dae);
		}
	}

}

ところが、org.hibernate.LazyInitializationException: could not initialize proxy - no Sessionのエラーがupdate、getメソッド実行時に発生した。
このエラーは次のように、Hibernateマッピングファイルのlazy属性に"false"を設定することで回避できた。lazy属性については、Hibernate2まではデフォルトで"false"だったのが、hibernate3から仕様が変わっている。

<hibernate-mapping package="sample.test">
	<class
		name="Employee"
		table="EMPLOYEE"
		lazy="false"
		
	>