EJB 3.0(Public Draft)入門記 Java Persistence API Chapter7 その2

7.2 Bootstrapping in J2SE Environments

J2SEの環境では、アプリケーションがPersistence.createEntityManagerFactoryを実行してEntityManagerFactoryを生成するそうです。Persistenceクラスは次のことをします。

  • コンテキストクラスパス上にあるすべての永続プロバイダサービスをlookupする
  • それぞれのPersistenceProviderをインスタンス化しPersistenceProviderのcreateEntityManagerFactoryメソッドを実行する。いずれかのPersistenceProviderのcreateEntityManagerFactoryメソッドがEntityManagerFactoryのインスタンスを返すまでつづける。
  • EntityManagerFactoryのインスタンスを呼び出し側に返す。いずれのプロバイダからもfactoryを取得できない場合はエラーとなる。

アプリケーションはPersistenceのメソッドを呼ぶだけで適切なEntityManagerFactoryを手に入れられるみたいですね。メソッドの呼び出しはこうなりますです。

  • アプリケーション -> Persistence -> PersistenceProvider

永続プロバイダは、すべてのparがpersistence.xmlを含んでいることや、エンティティのクラスがpersistence.xmlに一覧されていることを必要するかもしれないとのことです。このあたりは永続プロバイダごとにぜんぜん違ってもOKということかな。永続プロバイダがHibernateの場合は、parは必須ではなく、エンティティもpersistence.xmlに書かなくても大丈夫です。クラスパスにあるものを自動で認識してくれるみたいです。persistence.xmlは必須なのかも?


では、J2SE環境でPersistence APIを使ってみます。今回はEmbeddable EJB 3.0は使わず、Hibernate3.1とHibernate EntityManager3.1beta5の組み合わせを使います。Hibernate EntityManagerのテストをみるとpesistence.xmlの設定にはバリエーションがあるみたいですが一番かんたんに動きそうなやつでやってみます。

persistence.xmlはこんな感じ。persistence.xmlはMETA-INFの直下においてクラスパスに通るようにします。

<?xml version="1.0" encoding="UTF-8"?>
<entity-manager>
   <name>em</name>
  <properties>
    <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
    <property name="hibernate.connection.driver_class"  value="org.hsqldb.jdbcDriver"/>
    <property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost:1701"/>
    <property name="hibernate.connection.username" value="sa"/>
    <property name="hibernate.hbm2ddl.auto" value="create"/>
    <property name="hibernate.show_sql" value="true"/>
  </properties>
</entity-manager>

次に単純なエンティティを用意。

@Entity(access = AccessType.FIELD)
public class Customer {

  @Id(generate = GeneratorType.AUTO)
  private int id;

  private String name;

  public Customer() {    
  }

  public Customer(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getId() {
    return id;
  }
}

実行クラス。エンティティの永続化と取得を試してみました。

public class Main {

  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence
        .createEntityManagerFactory("em");

    try {
      EntityManager em = emf.createEntityManager();
      try {
        em.getTransaction().begin();
        em.persist(new Customer("hoge"));
        em.persist(new Customer("foo"));
        em.persist(new Customer("bar"));
        em.getTransaction().commit();
      } finally {
        em.close();
      }

      em = emf.createEntityManager();
      try {
        List<Customer> customers = em.createQuery(
            "select c from Customer c").getResultList();
        for (Customer c : customers) {
          System.out.println(c.getName());
        }
      } finally {
        em.close();
      }
    } finally {
      emf.close();
    }
  }
}

実行結果

Hibernate: insert into Customer (name, id) values (?, null)
Hibernate: call identity()
Hibernate: insert into Customer (name, id) values (?, null)
Hibernate: call identity()
Hibernate: insert into Customer (name, id) values (?, null)
Hibernate: call identity()
Hibernate: select customer0_.id as id3_, customer0_.name as name3_ from Customer customer0_
hoge
foo
bar

うごいた。設定がpersistence.xmlだけというのはシンプルでいいですね。でも、トランザクションの開始/終了とかEntityManagerのcloseとかは面倒くさいです。

PersistenceクラスはMETA-INF/services/javax.persistence.spi.PersistenceProviderを見て、永続プロバイダの実装(HibernatePersistence)を知るみたいです。META-INF/services/javax.persistence.spi.PersistenceProviderはhibernate-entitymanager.jarの中にあります。でもMETA-INF/services/javax.persistence.spi.PersistenceProviderのことはPublic Draftのドキュメントで触れられていないです。何でだろ。

追記
persistence.xmlhibernate.dialectの記述を忘れていたので追加しました。ないと動かないはずです。なんで記載し忘れたのかなぁ。
あと、persistence.xmlにprovider要素があることを忘れていました。これを設定すれば特定のPersistenceProvider実装が使われます。