Java EE 7 検証環境構築(6) JPA エンティティの作成と挿入

  1. Java EE 7 検証環境構築(1) WildFly + JBoss Tools で EARプロジェクトを作成し Arquillian で ユニットテストをグリーンにするところまで
  2. Java EE 7 検証環境構築(2) WildFly に DataSourceを作成
  3. Java EE 7 検証環境構築(3) JPAからMySQLに接続するユニットテストをArquillianで実行
  4. Java EE 7 検証環境構築(4) Java EE での DI(Dependency Injection) および CDI(Contexts and Dependency Injection)をながめる
  5. Java EE 7 検証環境構築(5) JBoss Toolsが生成したサンプルソースのCDIを確認する
  6. Java EE 7 検証環境構築(6) JPA エンティティの作成と挿入
  7. Java EE 7 検証環境構築(7) JPA 問い合わせ(1) 名前付きクエリを使ってみる。テストでトランザクションも意識する
  8. Java EE 7 検証環境構築(8) JPA 問い合わせ(2) 動的クエリとCriteria API を試す
  9. Java EE 7 検証環境構築(9) jBatch 概要をおさえる
  10. Java EE 7 検証環境構築(10) JBoss Tools で作成した EARプロジェクトをJava EE 6 から 7 に変更する
  11. Java EE 7 検証環境構築(11) jBatch用 プロジェクトの作成を行う
  12. Java EE 7 検証環境構築(12) jBatch 簡易サンプル作成と Arquillian でユニットテスト
  13. Java EE 7 検証環境構築(13) jBatch REST サービス経由で実行する
  14. Java EE 7 検証環境構築(14) WildFly の管理をGUIで行う
  15. Java EE 7 検証環境構築(15) WildFly を サービスとして設定する(Windows/Linux)
  16. Java EE 7 検証環境構築(16) WildFly と Apache を mod_jk で連携させる(Widows)

ここまでで、基本的に動作させることが出来るようになったので、JPA 周りの動きを見ていきたい。

CDIについての記述は物足りないにもほどがあったが、JPAについてはこの本の説明がわかりやすかった。

Beginning Java EE 6 GlassFish 3で始めるエンタープライズJava (Programmer's SELECTION)

環境を GlassFish から WildFly に変更したので、適宜読み替えながら、上記本の記述をかいつまみながら追っていこうと思う。

1.JPAの永続化を試してみる

1.1 エンティティの作成

だいたい、以下の様なJPAアノテーションを付加する。

  1. @Entity付与 でエンティティであることを認識させる
  2. @Id付与 で主キー設定
  3. @GeneratedValue で識別子の値を自動生成させる
  4. @Column でデフォルトのカラムマッピングをカスタマイズ

Bookエンティティを作成する。

@Entity
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;
	: コンストラクタ、ゲッター、セッター省略
}

1.2 サービスクラス(ステートレスセッションBean) を作成

Bookエンティティを操作するサービスクラスを作成してみる。

上記の本に書かれている訳ではない。

@Inject で、Logger と JPAの主役であるEntityManagerがインジェクトされているのは、CDIの仕組みによっている。

Java EE 7 検証環境構築(5) JBoss Toolsが生成したサンプルソースのCDIを確認する

@Stateless
public class BookService {

    @Inject
    private Logger log;

    @Inject
    private EntityManager em;
    
    public void insertBook(Book book) {
    	em.persist(book);
    }
}

1.3 Arquillian でユニットテストを実行

Java EE 7 検証環境構築(3) JPAからMySQLに接続するユニットテストをArquillianで実行

単純にBookエンティティを挿入してみる。

@RunWith(Arquillian.class)
public class BookServiceTest {
	   @Deployment
	    public static Archive<?> createTestArchive() {
	        return ShrinkWrap.create(WebArchive.class, "test.war")
	                .addClass(Resources.class)
	                .addClass(Book.class)
	                .addClass(BookService.class)
	                .addAsResource("META-INF/test-persistence.xml", "META-INF/persistence.xml")
	                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
	                ;
	    }

	    @Inject
	    Logger log;

	    @Inject
	    BookService bookService;
	    
	    @Test
	    public void insertBookTest() {
	    	Book book = new Book();
	    	
	    	book.setTitle("Test Book");
	    	book.setPrice(150f);
	    	book.setDescription("this is test book.");
	    	
	    	bookService.insertBook(book);
	    	
	    }
}

JPAがはき出すSQL

10:28:44,068 INFO  [org.hibernate.tool.hbm2ddl.SchemaExport] (ServerService Thread Pool -- 20) HHH000227: Running hbm2ddl schema export
10:28:44,072 INFO  [stdout] (ServerService Thread Pool -- 20) Hibernate: drop table if exists Book
10:28:44,089 INFO  [stdout] (ServerService Thread Pool -- 20) Hibernate: drop table if exists hibernate_sequence
10:28:44,506 INFO  [stdout] (ServerService Thread Pool -- 20) Hibernate: create table Book (id bigint not null, description longtext, illustrations bit, isbn varchar(255), nbOfPage integer, price float, title varchar(255) not null, primary key (id))
10:28:45,221 INFO  [stdout] (ServerService Thread Pool -- 20) Hibernate: create table hibernate_sequence ( next_val bigint )
10:28:45,825 INFO  [stdout] (ServerService Thread Pool -- 20) Hibernate: insert into hibernate_sequence values ( 1 )
10:28:50,408 INFO  [stdout] (default task-1) Hibernate: select next_val as id_val from hibernate_sequence for update
10:28:50,423 INFO  [stdout] (default task-1) Hibernate: update hibernate_sequence set next_val= ? where next_val=?
10:28:50,574 INFO  [stdout] (default task-1) Hibernate: insert into Book (description, illustrations, isbn, nbOfPage, price, title, id) values (?, ?, ?, ?, ?, ?, ?)

テスト成功

jpa_junit01

1.4 MySQL に接続して、どのようなDDLが生成されたか見てみる

@Column で指定しないと、デフォルトの桁数などが使用されているのが見て取れる。

PS C:\Users\piroto> mysql -u root -p
Enter password: ********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.6.17 MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use tallarico
Database changed
mysql> show tables;
+---------------------+
| Tables_in_tallarico |
+---------------------+
| book                |
| hibernate_sequence  |
| registrant          |
+---------------------+
3 rows in set (0.00 sec)

mysql> show create table book;
+-------+-------------------------------------
| Table | Create Table
+-------+-------------------------------------
| book  | CREATE TABLE `book` (
  `id` bigint(20) NOT NULL,
  `description` longtext,
  `illustrations` bit(1) DEFAULT NULL,
  `isbn` varchar(255) DEFAULT NULL,
  `nbOfPage` int(11) DEFAULT NULL,
  `price` float DEFAULT NULL,
  `title` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 
+-------+-------------------------------------
1 row in set (0.00 sec)

WildFly では、デフォルトのJPA実装は Hibernte ということ(HibernateがJPAインターフェースを備えている)で、少し古いが以下の本を購入してみた。読了はしていないが、前半部分だけでも、かなり良書。ORMとはなんたるかがよくわかる。

今までかなりORMを誤解していた部分があった。ORM結構面白そう。