ちょっと思うところがあって、JPAの簡単なサンプルを書いてみました。
JPAは、1.0の頃にちょこっと本を見て書いたことがあるだけで、ほとんど覚えていません。仕事でも使っていませんし。
で、とりあえずJava EEサーバにデプロイなんて考えずに、Java SEの範囲で動かすことを考えます。ただ、書くのはScalaでですが…。
JPAの実装には、Hibernateを選びました。最近触っているのがデータグリッドなので、このあたりにJPAに興味を持ったの理由が見え隠れしてるかも?
Hibernate
http://www.hibernate.org/hibernate
データベースはMySQLです。このために、久々にインストール。
対象のテーブルは、こんな感じ。今回は、ホントに簡単なサンプルなので。
CREATE TABLE user ( id INT(9), first_name VARCHAR(10), last_name VARCHAR(10), age INT(3), version_no INT, PRIMARY KEY(id) );
では、build.sbt。
name := "jpa-example" version := "0.0.1-SNAPSHOT" scalaVersion := "2.10.3" organization := "littlewings" resolvers += "Public JBoss Group" at "http://repository.jboss.org/nexus/content/groups/public-jboss" libraryDependencies ++= Seq( "org.hibernate" % "hibernate-entitymanager" % "4.2.7.SP1", "mysql" % "mysql-connector-java" % "5.1.26" % "runtime" )
JPAの設定ファイルである、永続ユニットの定義です。
src/main/resources/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="jpa.example" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" /> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=utf8" /> <property name="javax.persistence.jdbc.user" value="kazuhira" /> <property name="javax.persistence.jdbc.password" value="password" /> </properties> </persistence-unit> </persistence>
ユーザ名とかパスワードとか、Hibernateのドキュメントを見ていると固有のプロパティの例ばかりでしたが、JPAっぽいプロパティ名でも動きました。
で、エンティティクラスの定義。
@SerialVersionUID(1L) @Entity(name = "user") class User( @(Id @beanGetter) @BeanProperty var id: Int, @(Column @beanGetter)(name = "first_name") @BeanProperty var firstName: String, @(Column @beanGetter)(name = "last_name") @BeanProperty var lastName: String, @(Column @beanGetter) @BeanProperty var age: Int, @(Column @beanGetter)(name = "version_no") @(Version @beanGetter) @BeanProperty var versionNo: Int = 1 ) extends Serializable { def this() = this(0, null, null, 0, 1) override def toString(): String = s"id = $id, firstName = $firstName, lastName = $lastName, age = $age, versionNo = $versionNo" }
エンティティにはデフォルトコンストラクタが要求されることや、各種アノテーションを付けたフィールドがgetterとかに付かないとまともに動作しなかったので、最初はこんな形に。
Scala的にはコンストラクタで設定して…といきたかったのですが、デフォルトコンストラクタが必須な分だけ、この定義はダサいですね…。
仕方がないので、ここは諦めてこんな定義に。
object User { def apply(id: Int, firstName: String, lastName: String, age: Int): User = { val user = new User user.id = id user.firstName = firstName user.lastName = lastName user.age = age user } } @SerialVersionUID(1L) @Entity @Table(name = "user") class User extends Serializable { @Id @BeanProperty var id: Int = _ @Column(name = "first_name") @BeanProperty var firstName: String = _ @Column(name = "last_name") @BeanProperty var lastName: String = _ @Column @BeanProperty var age: Int = _ @Column(name = "version_no") @Version @BeanProperty var versionNo: Int = _ override def toString(): String = s"id = $id, firstName = $firstName, lastName = $lastName, age = $age, versionNo = $versionNo" }
ここは、コンパニオンオブジェクトを使ってしまおうってことで。
そうそう、今回の例で初めて@beanGetterとか、他の@field、@getterアノテーションとかを知ったんですよね。たまには他のものに手を出してみるのいいですね〜。
*あとで見直したら、なんか@beanGetterとかいらないことがわかりました…
EntityManagerを使ったサンプルは、こちらです。いやまあ、全然大したことしてませんけど。
object JpaExample { def main(args: Array[String]): Unit = { val entityManagerFactory = Persistence.createEntityManagerFactory("jpa.example") val entityManager = entityManagerFactory.createEntityManager() val transaction = entityManager.getTransaction transaction.begin() val query = entityManager.createQuery("SELECT u FROM User u") query.getResultList.asScala.foreach { case u: User => println(s"User: $u") // entityManager.detach(u) } entityManager.clear() entityManager.createQuery("DELETE FROM User").executeUpdate() val users = Array( User(1, "カツオ", "磯野", 11), User(2, "ワカメ", "磯野", 9), User(3, "タラオ", "フグ田", 3) ) users.foreach(entityManager.persist) transaction.commit() entityManager.close() entityManagerFactory.close() } }
EntityManagerの永続性コンテキストってやつですか?そのあたりが全然わかってないので、ちょっと本を読みながら勉強してみようと思います。
Beginning Java EE 6~GlassFish 3で始めるエンタープライズJava (Programmer's SELECTION)
- 作者: Antonio Goncalves,日本オラクル株式会社,株式会社プロシステムエルオーシー
- 出版社/メーカー: 翔泳社
- 発売日: 2012/03/09
- メディア: 大型本
- 購入: 5人 クリック: 147回
- この商品を含むブログ (29件) を見る
でも、近くデータグリッドと組み合わせるかも?
今回の、サンプルコード全体です。
import scala.collection.JavaConverters._ import scala.beans.BeanProperty import javax.persistence.{Column, Entity, Id, Persistence, Version} object JpaExample { def main(args: Array[String]): Unit = { val entityManagerFactory = Persistence.createEntityManagerFactory("jpa.example") val entityManager = entityManagerFactory.createEntityManager() val transaction = entityManager.getTransaction transaction.begin() val query = entityManager.createQuery("SELECT u FROM User u") query.getResultList.asScala.foreach { case u: User => println(s"User: $u") // entityManager.detach(u) } entityManager.clear() entityManager.createQuery("DELETE FROM User").executeUpdate() val users = Array( User(1, "カツオ", "磯野", 11), User(2, "ワカメ", "磯野", 9), User(3, "タラオ", "フグ田", 3) ) users.foreach(entityManager.persist) transaction.commit() entityManager.close() entityManagerFactory.close() } } object User { def apply(id: Int, firstName: String, lastName: String, age: Int): User = { val user = new User user.id = id user.firstName = firstName user.lastName = lastName user.age = age user } } @SerialVersionUID(1L) @Entity @Table(name = "user") class User extends Serializable { @Id @BeanProperty var id: Int = _ @Column(name = "first_name") @BeanProperty var firstName: String = _ @Column(name = "last_name") @BeanProperty var lastName: String = _ @Column @BeanProperty var age: Int = _ @Column(name = "version_no") @Version @BeanProperty var versionNo: Int = _ override def toString(): String = s"id = $id, firstName = $firstName, lastName = $lastName, age = $age, versionNo = $versionNo" }