Entity Beansは、「永続化」されているデータとの対応に用いるEJBです。
こうした技術は、よく"O/R Mapping"と呼ばれています。これは、リレーショナルデータベースのテーブルの1行と、Entity Beanの(基本的には)ひとつのインスタンスが対応することを指します。そして、リレーショナルデータベースとEntity Beanの間で同期が行われます。
EJB 3.0では、Entity Beanに"Java Persistence API"が用いられます。
企業の従業員を表すテーブルがあります。
create table emp ( empno DECIMAL(4) primary key, ENAME VARCHAR(10), SAL DECIMAL(10, 2) );
ここでは、このテーブルに対応するEntity Beanについて考えてみましょう。重要なのは、ソースコード中のAnnotationと、テーブルの項目との対応関係です。じっくり見比べてみてください。
import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.Id; import javax.persistence.Column; // Entity Bean である @Entity // EMP テーブルと関連づけられる @Table(name = "EMP") public class Employee implements Serializable { private int empNo; private String eName; private double sal; // empNoプロパティは Entity BeanのIDである。 // これは、RDB中では主キーとなる。 @Id // empNo プロパティは、テーブル中の // EMPNO項目とマッピングしている。 @Column(name = "EMPNO") public int getEmpNo() { return empNo; } // これ以降、テーブル中の各項目に対応する // setter と getter (= プロパティ) を用意 // プロパティとテーブル中の項目名が同一の場合は // アノテーションをつける必要はない public void setEmpNo(int empNo) { this.empNo = empNo; } public String getEname() { return eName; } public void setEname(String eName) { this.eName = eName; } public double getSal() { return sal; } public void setSal(double sal) { this.sal = sal; } }
このEntity Beanでは、テーブル名、主キー、項目名といったリレーショナルデータベースのテーブル中の情報が、Annotationに記述されています。旧来のEntity Beanでは、こうした情報は設定ファイルに記述されていました。
もともと、オブジェクト指向であるJavaプログラムと、リレーショナルデータベースのテーブルとでは情報の管理方法が違うため、テーブルの持つすべての情報をJavaプログラムに持たせることは不可能でした。そのため、設定ファイルが必要になるのです。このことは「インピーダンス・ミスマッチ」と呼ばれています。
しかし、テーブルの持つ情報をAnnotationにしてJavaプログラムに加えることで、Javaプログラムはテーブルの持つ情報をそのまま持つことができるようになります。インピーダンス・ミスマッチが解消されます。
Entity Beanを使ったプログラムでは、クライアントがEntity Beanを直接操作するのではなく、Stateless Session BeanからEntity Beanにアクセスできるようにします。この結果、データベースに関連するさまざまな処理を隠蔽することができます。
これが「Session Facadeパターン」です。
では、まずEmployeeFacadeインタフェースです。
import javax.ejb.Remote; @Remote public interface EmployeeFacade { public void addEmployee(int empNo, String name, double salary); public Employee findEmployeeByEmpNo(int empNo); }
次に、このインタフェースを実装したStateless Session Beanです。
import javax.ejb.Stateless; import javax.persistence.PersistenceContext; import javax.persistence.EntityManager; @Stateless public class EmployeeFacadeBean implements EmployeeFacade { @PersistenceContext(unitName="summer2006") private EntityManager em; public Employee findEmployeeByEmpNo(int empNo) { return em.find(Employee.class, empNo); } public void addEmployee(int empNo, String eName, double sal) { Employee emp = new Employee(); emp.setEmpNo(empNo); emp.setEname(eName); emp.setSal(sal); em.persist(emp); } }
このStateless Session Beanから、Entity Beanにアクセスしています。
まず注目していただきたいのが、この部分です。
@PersistenceContext(unitName="summer2006") private EntityManager em;
EntityManagerは、データの永続管理を受け持つオブジェクトです。データベースと接続して、さまざまな処理を行います。@PersistenceContextは、Dependency Injection (依存性注入)を行うためのAnnotationです。EntityManagerは、コンテナから依存性注入されます。
public Employee findEmployeeByEmpNo(int empNo) { return em.find(Employee.class, empNo); }
EntityManagerのfindメソッドは、データベースからempNoという主キーで指定したデータを検索し、検索結果としてEmployeeオブジェクトを返します。
public void addEmployee(int empNo, String eName, double sal) { Employee emp = new Employee(); emp.setEmpNo(empNo); emp.setEname(eName); emp.setSal(sal); em.persist(emp); }
EntityManagerのpersistメソッドで、Entity Beanを永続化しています。つまり、データをデータベースで管理するようにしているのです。
クライアントプログラムです。特に解説は必要ないでしょう。
このプログラムでは、Entity Beanのことをまったく気にせずに処理を記述できることがわかりますね。
import javax.ejb.EJB; public class EmployeeClient { @EJB static EmployeeFacade ef; public static void main(String[] args) { try { int empNo = Integer.parseInt(args[0]); String name = args[1]; double sal = Double.parseDouble(args[2]); ef.addEmployee(empNo, name, sal); } catch (Exception e) { System.err.println("Correct arguments not received, exiting"); e.printStackTrace(); System.exit(0); } } }
Entity Beanからデータベースにアクセスするには、その設定をきちんと記述する必要があります。
GlassFishには、リレーショナルデータベース管理システムとしてJavaDB (Apache Derby)が付属しています。今回はこれを使いましょう。
まずはじめに、リレーショナルデータベースにアクセスするためのコネクションを用意します。
ここでは、作成したコネクションにJNDI名をつけます。
次に、JavaDBにアクセスしてみましょう。ここでテーブルを作成します。
connect \ 'jdbc:derby://localhost:1527/summer2006;create=true;user=APP;password=APP'; \
create table emp ( empno DECIMAL(4) primary key, ENAME VARCHAR(10), SAL DECIMAL(10, 2) );
Java Persistence APIを使うときには、"persistence.xml"というファイルを編集する必要があります。このファイルではさまざまな設定情報を記述することができます。今回のサンプルでは、先に設定した"jdbc/Summer2006"というJDBCリソースがJavaDBで使われているということを明示化しています。
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="summer2006"> <jta-data-source>jdbc/Summer2006</jta-data-source> <properties> <property name="toplink.platform.class.name" value="oracle.toplink.essentials.platform.database.DB2Platform"/> </properties> </persistence-unit> </persistence>
このファイルは、コンテナに配備するJarファイルの"META-INF"ディレクトリの中に置く必要があります。次のようにJarファイルを作成すればよいでしょう。
jar cvf employee.jar *.class META-INF/persistence.xml
EmployeeFacadeBeanの@PersistenceContextというAnnotationには、unitNameというメンバがありました。
@Stateless public class EmployeeFacadeBean implements EmployeeFacade { @PersistenceContext(unitName="summer2006") private EntityManager em; ............ }
この値は、"summer2006"となっています。これは、先のpersistence.xmlのpersistence-unit要素にあるname属性の値になっています。
このようにして、persistence.xmlの内容がEntityManagerに依存性注入されているのです。