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>
テストケースの作成
- プロジェクトのプロパティ画面でJavaのビルドパスにJUnitライブラリを追加する。ライブラリーのタブをクリックし、「ライブラリー追加」ボタンを押してJUnitを選択する。
- ソースフォルダーを右クリック、新規→作成を選択、ウィザード選択でJava配下のJUnitテスト・ケースを選択する。
- JUnitテストケース画面で名前とテスト元クラスを入力して「次へ」ボタンを押す。
- テスト・メソッド画面でテストを行うEmployeeImplクラスのメソッドをチェックし、「終了」ボタンを押すとテストケースの雛形が作成される。
- 雛形を次の内容で修正し、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" >