Powered by SmartDoc

Entity Bean

Entity Bean

Entity Beansは、「永続化」されているデータとの対応に用いるEJBです。

こうした技術は、よく"O/R Mapping"と呼ばれています。これは、リレーショナルデータベースのテーブルの1行と、Entity Beanの(基本的には)ひとつのインスタンスが対応することを指します。そして、リレーショナルデータベースとEntity Beanの間で同期が行われます。

EJB 3.0では、Entity Beanに"Java Persistence API"が用いられます。

Entity Bean の作成

企業の従業員を表すテーブルがあります。

create table emp (
	empno		DECIMAL(4) primary key,
	ENAME		VARCHAR(10),
	SAL			DECIMAL(10, 2)
);

ここでは、このテーブルに対応するEntity Beanについて考えてみましょう。重要なのは、ソースコード中のAnnotationと、テーブルの項目との対応関係です。じっくり見比べてみてください。

Employee.java
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プログラムはテーブルの持つ情報をそのまま持つことができるようになります。インピーダンス・ミスマッチが解消されます。

Session Facade と EntityManager

Entity Beanを使ったプログラムでは、クライアントがEntity Beanを直接操作するのではなく、Stateless Session BeanからEntity Beanにアクセスできるようにします。この結果、データベースに関連するさまざまな処理を隠蔽することができます。

これが「Session Facadeパターン」です。

では、まずEmployeeFacadeインタフェースです。

EmployeeFacade.java
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です。

EmployeeFacadeBean.java
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のことをまったく気にせずに処理を記述できることがわかりますね。

EmployeeClient.java
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)が付属しています。今回はこれを使いましょう。

コネクションプールを作成する

まずはじめに、リレーショナルデータベースにアクセスするためのコネクションを用意します。

  1. GlassFishを起動して、http://localhost:4848/にアクセスします。
  2. ログインします。デフォルトではユーザ名がadminで、パスワードがadminadminです。
  3. 左側メニューの"Resources"を選択します。
  4. "JDBC"→"Connection Pools"を選択します。
  5. "New"をクリックします。
  6. "Name"には適切な名前を入力します。今回は"Summer2006Pool"にしましょう。
  7. "Resource Type"では"javax.sql.DataSource"を選択します。
  8. "Database Vendor"では"JavaDB"を選択します。
  9. "Next"をクリックします。
  10. "Properties"を編集します。
  11. "User"と"Password"にそれぞれ"APP"と入力します。
  12. "ServerName"には適切な名前を入力します。今回は"localhost"にします。
  13. "DatabaseName"には適切な名前を入力します。今回は"summer2006"にします。
  14. "ConnectionAttributes"に";create=true"と入力します。
  15. "Finish"をクリックします。

JDBCリソースの設定

ここでは、作成したコネクションにJNDI名をつけます。

  1. 左側メニューの"JDBC Resources"を選択します。
  2. "New"をクリックします。
  3. "JNDI Name"には適切な名前を入力します。今回は"jdbc/Summer2006"にします。
  4. "Pool Name"には、先に作成した"Summer2006Pool"を選択します。
  5. "OK"をクリックします。

JavaDBへのアクセス

次に、JavaDBにアクセスしてみましょう。ここでテーブルを作成します。

  1. JavaDBは"asadmin start-database"コマンドで起動できます。
  2. %JAVAEE_HOME%\javadb\frameworks\NetworkServer\binに移動します。
  3. ij.bat (Unix系OSの場合はij.ksh)を編集します。
  4. "DERBY_INSTALL="の後にJavaDBがインストールされているディレクトリを指定します。例えば"%JAVAEE_HOME%\javadb"です。この項目のコメントアウトを解除し、保存します。
  5. コマンドプロンプトなどを使ってij.bat (ij.ksh)を起動します。
  6. プロンプトが表示されたら、SQLを入力できます。まず次のSQLを入力します。
    connect \
        'jdbc:derby://localhost:1527/summer2006;create=true;user=APP;password=APP'; \
    
  7. 次のSQLを入力して、テーブルを作成します。
    create table emp (
    	empno		DECIMAL(4) primary key,
    	ENAME		VARCHAR(10),
    	SAL			DECIMAL(10, 2)
    );
    

persistence.xml の作成

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

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に依存性注入されているのです。