Topics
Enterprise Architecture
Spring 2.0でのJPA(Java Persistence API)の利用
Pages:
1,
2,
3,
4,
5,
6
医療記録管理アプリケーション(MedRec)では、永続化が必要なドメインモデルクラス(
Patient、
Prescription、
Record、
User)ごとに1つずつ、合計4つの異なるDAOを使用します。これらDAOの実装クラスはそれぞれ、
JpaPatientDAO、
JpaPrescriptionDAO、
JpaRecordDAO、
JpaUserDAOで、
com.bea.medrec.dao.ormパッケージに入っています。
それでは、Patient DAOの詳細を調べて、動作の仕組みを把握しましょう。以下に示すのは、医療記録管理アプリケーションにおける患者データの検索や更新の処理に使用されるデータアクセスオブジェクトのインタフェースです。
public interface PatientDao {
public Patient getById(Integer patientId)
throws DataAccessException;
public List getByEmail(String email)
throws DataAccessException;
public List getByLastName(String lastName)
throws DataAccessException;
public List getByLastNameFirstName(String lastName,
String firstName) throws DataAccessException;
public List getByLastNameWild(String lastName)
throws DataAccessException;
public Patient getBySsn(String ssn)
throws DataAccessException;
public List getByStatus(String status)
throws DataAccessException;
public Patient getByUsername(String username)
throws DataAccessException;
public Patient save(Patient patient)
throws DataAccessException;
public Patient update(Patient patient)
throws DataAccessException;
}
Patient DAOインタフェースがPOJI(Plain Old Java Interface)であることに注意してください。使用される永続化技術(今回の場合はJPA)に固有のJava型を拡張することもインポートすること もありません。Patient DAOメソッドの大半は、患者のリストか単一の患者オブジェクトを返すクエリを実行します。最後の2つのメソッドはそれぞれ、データベースへの新規患者の 保存と、データベースに格納されている既存患者の情報の更新に使用されます。
このインタフェースの各メソッドでは
DataAccessExceptionの送出を宣言していますが、これはSpring Frameworkで定義されている実行時例外です。
DataAccessExceptionに は、注意すべき点が2つあります。まず第1に、これは実行時例外であるため、データアクセスオブジェクトを使用するアプリケーションコードでは、JDBC やEJB 2.xエンティティBeanの場合のように、それぞれの呼び出しをtry-catchブロックで囲む必要はありません。第2に、基礎となる永続化技術で使 用される特定の例外クラスが
DataAccessExceptionによってラップされることで、アプリケーションの残りの部分が永続化レイヤとの独立性を保つことができるため、好都合です。
インタフェースについては、これくらいにしておきます。では次に、Patient DAOの実装に目を向けましょう。以下に示すのは基本クラス
BaseDAOで、MedRecのすべてのデータアクセスオブジェクトがこれを拡張します。
package com.bea.medrec.dao.orm;
import org.springframework.orm.jpa.support.JpaDaoSupport;
public abstract class BaseDao extends JpaDaoSupport {
...
}
今回の場合、これは非常にシンプルなクラスになりますが、一般に、さまざまなデータアクセスオブジェクト実装に共通のコードであれば、どのようなものにも使用できます。
BaseDAOはSpringの
JpaDaoSupportクラスを拡張します。これによりDAO実装クラスからSpringのJPA固有のAPIにアクセスできるようになるので、これはなくてはならないものです。
Patient DAOの実装クラス
JpaPatientDaoは、以下のように
BaseDaoを拡張します。
public class JpaPatientDao extends BaseDao implements PatientDao {
public Patient getById(Integer pId)
throws DataAccessException {
return getJpaTemplate().find(Patient.class, pId);
}
public List getByLastName(String pLastName)
throws DataAccessException {
List patients = getJpaTemplate().find(
"SELECT p " +
"FROM " + Patient.class.getSimpleName() + " p " +
"WHERE p.lastName LIKE ?1", pLastName);
return (patients.isEmpty())?
Collections.EMPTY_LIST : patients;
}
...
}
このサンプルコードにはまた、2つのクエリメソッドの典型的な実装も示されています。まず、
getById()は、一意な識別子フィールドで患者をルックアップします。それには、Springの
JpaTemplateに定義されている特別な検索メソッドfind()を呼び出します。このメソッドは、
Patientクラスと一意なIDをパラメータとして受け取り、そのIDを持つ
Patientオブジェクトを返します。一方、
getByLastName()メソッドは、指定された値と似た姓を持つPatientオブジェクトのリストを返します。
getByLastName()では
JpaTemplate.find()の 別のバージョンが使用されますが、そちらのほうは、EJB QLクエリとクエリパラメータをメソッドパラメータとして受け取り、そのクエリに一致するオブジェクトのリストを返します。また、患者DAOの保存メソッ ドsave()と更新メソッドupdate()は以下のようになります。
public class JpaPatientDao extends BaseDao implements PatientDao {
...
public Patient save(Patient pPatient)
throws DataAccessException {
getJpaTemplate().persist(pPatient);
return pPatient;
}
public Patient update(Patient pPatient)
throws DataAccessException {
return getJpaTemplate().merge(pPatient);
}
}
Patient DAOの
saveメソッドと
updateメソッドの上記実装では、
save()メソッドがデータベースへの新規患者レコードの挿入に使用されるのに対して、
update()は既存の患者レコードを変更します。各メソッドはそれぞれ、新しい
Patientオブジェクトと更新された
Patientオ ブジェクトの参照を返します。なお、persistメソッドとmergeメソッドを実行しても、それが直ちにデータベースの更新につながるわけではないこ とを理解しておくことが重要です。変更内容は、現在のトランザクションがコミットされるまでJPAによりキャッシュされるのが普通です。コミットされた ら、変更内容が一括してデータベースに送信されますが、保留中の変更内容は、クエリが実行されるたびにフラッシュされることのほうが多いでしょう。
興味深いことに、すべてのデータアクセス操作でSpringテンプレートが使用され、それが内部的にJPAに委譲されるので、Patient DAOオブジェクトはいかなるJPA API にもほとんど依存しません。実際に、JPAへの直接の依存関係と言えば、
getByLastName()メソッドで使用されるEJB QLクエリ文字列くらいしか、これまでにお目にかかったことはありません。また、先ほどSpring DAOはPOJOであると言いましたが、実際にはDAOはSpringの
JpaDaoSupportク ラスを拡張する必要があるので、この言い方は完全に正しいわけではないことにも注意してください。とは言え、ここで重要なのは、アプリケーションの残りの 部分にとってDAOにより公開されるインタフェースは、JPAやSpringの型に依存しないPOJI(Plain Old Java Interface)であることです。