JPAのお勉強 その1

書籍『Beginning Java EE 6 Platform with GlassFish 3』CHAPTER 2:Java Persistenceについて。

説明と共に環境を用意しなきゃならんって事で、Eclipse3.5で以下の手順で取りあえずJPAが動く環境を用意。

  • [ファイル]→[新規]→[プロジェクト]→[JavaEE]→[エンタープライズ・アプリケーション・プロジェクト]でEARプロジェクトを作成。以下の内容を設定、[次へ]押下
    • プロジェクト名:[cd-bookstore-ear]
    • ターゲット・ランタイム:[GlassFish v3 Java EE 6]
    • EARバージョン:[5.0]
    • 構成:GlassFish v3 Java EE 6 デフォルト構成
  • モジュール依存関係は特に指定せず、そのまま[完了]押下
  • 引き続きプロジェクト作成。[ファイル]→[新規]→[プロジェクト]→[EJB]→[EJBプロジェクト]を選択、[次へ]押下。
    • プロジェクト名:[cd-bookstore-ejb]
    • EJBモジュール・バージョン:[3.0]
    • 構成:GlassFish v3 Java EE 6 デフォルト構成の状態で[変更]ボタン押下
      • プロジェクト・ファセットの中から[Java永続化]を選択し、[OK]を押下
      • [カスタム]となった状態で[次へ]を押下
    • EARメンバーシップ:"EARにプロジェクトを追加"を選択、EARプロジェクトとして[cd-bookstore-ear]を選択
  • ソースフォルダの選択:既存の[ejbModule]を除去、[src/main/java]を新規追加し[次へ]押下
  • EJBクライアントJARの設定:以下の内容で[次へ]押下
    • [Create an EJB...]の選択はご自由に。取りあえずチェックは外しておいた
    • ejb-jarデプロイメント記述子の生成にチェック
  • JPAファセットに関する設定は全てデフォルトのまま、[完了]押下
    • デフォルトだと型が[EclipseLink 1.1]となるが、書籍でもEclipseLinkを利用しているので問題無し。
  • Javaエンティティクラスの作成。(src/main/java com.apress.javaee6.chapter02.Book.java)
package com.apress.javaee6.chapter02;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name = "BOOK")
@NamedQuery(name = "findAllBooks", query = "SELECT b FROM Book b")
public class Book {

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String title;

    private Float price;

    @Column(length = 2000)
    private String description;
    private String isbn;
    private Integer nbOfPage;
    private Boolean illustrations;

    // setter,getterメソッドは自動生成:割愛。
}
  • Java実行クラスの作成。(src/main/java com.apress.javaee6.chapter02.Main.java)
package com.apress.javaee6.chapter02;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class Main {
    public static void main(String[] args) {

        Book book = new Book();
        book.setTitle("The Hitchhiker's Guide to the Galaxy.");
        book.setPrice(12.5F);
        book.setDescription("Science fiction comedy book");
        book.setNbOfPage(354);
        book.setIsbn("1-84023-742-2");
        book.setIllustrations(false);

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("chapter02PU");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();
        em.persist(book);
        tx.commit();

        em.close();
        emf.close();

    }
}
  • 永続化設定ファイル(src/main/java META-INF/persistence.xml)。
<?xml version="1.0" encoding="UTF-8"?>

<persistence
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">

    <persistence-unit name="chapter02PU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.apress.javaee6.chapter02.Book</class>
        <properties>
            <property name="eclipselink.target-database" value="DERBY" />
            <property name="eclipselink.ddl-generation" value="create-tables" />
            <property name="eclipselink.logging.level" value="FINE" />
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/chapter02DB;create=true"/>
            <property name="javax.persistence.jdbc.user" value="APP" />
            <property name="javax.persistence.jdbc.password" value="APP" />
        </properties>
    </persistence-unit>

</persistence>

実行時にはDerbyのサーバ起動を行っておくこと。Mainクラス実行でDBに1件データが登録されます。


続いてテスト実行。(src/test/java com.apress.chapter02.BookTest.java)

package com.apress.chapter02;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.apress.javaee6.chapter02.Book;

public class BookTest {

    private static EntityManagerFactory emf;
    private static EntityManager em;
    private static EntityTransaction tx;

    @BeforeClass
    public static void initEntityManager() throws Exception {
        emf = Persistence.createEntityManagerFactory("chapter02PU");
        em = emf.createEntityManager();
    }

    @AfterClass
    public static void closeEntityManager() throws Exception {
        em.close();
        emf.close();
    }

    @Before
    public void initTransaction() {
        tx = em.getTransaction();
    }

    @Test
    public void shouldCreateABook() throws Exception {
        Book book = new Book();
        book.setTitle("The Hitchhiker's Guide to the Galaxy.");
        book.setPrice(12.6F);
        book.setDescription("Science fiction comedy book");
        book.setNbOfPage(354);
        book.setIsbn("1-84023-742-2");
        book.setIllustrations(false);

        tx.begin();
        em.persist(book);
        tx.commit();
        assertNotNull("ID should not be null", book.getId());

        List<Book> books = em.createNamedQuery("findAllBooks").getResultList();
        assertEquals(1, books.size());
    }
}

JUnit実行でテストが全て通る事を確認。Mainクラス→Testクラスの順で実行するとデータ不整合になるかもしれないのでその辺は適宜調整で。

実行には上記環境の他に、以下のJARライブラリが必要。クラスパスを通した上で実行してください。

書籍はCHAPTER2〜4までJPAに関する記述有り。なので次もJPAです。