ScalaでHibernateを使う

ScalaからHibernateを使ってみる。

利用するライブラリ

利用するライブラリは以下

  • antlr-2.7.6.jar
  • commons-collections-3.1.jar
  • commons-lang-2.4.jar
  • dom4j-1.6.1.jar
  • ejb3-persistence.jar
  • h2-1.1.117.jar
  • hibernate3.jar
  • hibernate-annotations.jar
  • hibernate-commons-annotations.jar
  • javassist-3.9.0.GA.jar
  • jta-1.1.jar
  • slf4j-api-1.5.8.jar
  • slf4j-jdk14-1.5.8.jar

ライブラリが依存関係を含めて不足していると、Scalaコンパイルが通らないことがあるので注意

Entityの作成

ポイントはアノテーションの属性名としてvalを付けて記述すること。

import javax.persistence._

@Entity
@Table{ val name="product" }
class Product(n: String) {
  def this() = this("")

  @Id @GeneratedValue{ val strategy=GenerationType.IDENTITY }
  var id : Int = _
  var name : String = n
  
  override def toString = "Product: " + id + " " + name
}

hibernate.cfg.xml

ソースフォルダ直下にhibernate.cfg.xmlを作成(Eclipse使用)
例によって、hibernate.hbm2ddl.autoでDDL自動実行

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <property name="connection.driver_class">org.h2.Driver</property>
        <property name="connection.url">jdbc:h2:tcp://localhost:9092/hibernate</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>
        <property name="dialect">org.hibernate.dialect.H2Dialect</property>
        <property name="current_session_context_class">thread</property>
        
        <property name="hibernate.hbm2ddl.auto">create</property>
        <property name="hibernate.show_sql">true</property>
        
        <mapping class="etc9.Product"/>
    </session-factory>
</hibernate-configuration>

実行オブジェクト

H2を起動し、DB操作を行う。

import scala.xml._
import org.hibernate._
import org.hibernate.cfg._

object ProductTest {
  def main(args : Array[String]) : Unit = {
    val tcpServer = org.h2.tools.Server.createTcpServer(
        Array("-baseDir", "db\\h2", "-tcpPort", "9092"))
    tcpServer.start
    operateDb
    tcpServer.shutdown
  }
  
  lazy val sessionFactory = (new AnnotationConfiguration).configure.buildSessionFactory
  def operateDb = {
    withTxSession(session => {
      val p1 = new Product("Scala1")
      session.save(p1)
      val p2 = new Product("Scala2")
      session.save(p2)
      val eIter = session.createQuery("from Product").list.iterator
      while (eIter.hasNext) {
        val p = eIter.next.asInstanceOf[Product]
        println(p)
      }
    })
  }

  def withTxSession(f:(Session) => Any) = {
    val s = sessionFactory.getCurrentSession
    val t = s.beginTransaction
    val r = f(s)
    t.commit
    r
  }
}

実行結果は、

Hibernate: insert into product (id, name) values (null, ?)
Hibernate: insert into product (id, name) values (null, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from product product0_
Product: 1 Scala1
Product: 2 Scala2

hibernate.cfg.xmlファイル無し

ScalaはXMLリテラルで扱えるので、ソースファイルにHibernate設定を記述してみる。

package etc9

import scala.xml._
import org.hibernate._
import org.hibernate.cfg._

object ProductTest {
  def main(args : Array[String]) : Unit = {
    val tcpServer = org.h2.tools.Server.createTcpServer(
        Array("-baseDir", "db\\h2", "-tcpPort", "9092"))
    tcpServer.start
    operateDb
    tcpServer.shutdown
  }

  lazy val sessionFactory = (new AnnotationConfiguration).configure.buildSessionFactory
  def operateDb = {
    withTxSession(session => {
      val p1 = new Product("Scala1")
      session.save(p1)
      val p2 = new Product("Scala2")
      session.save(p2)
      val eIter = session.createQuery("from Product").list.iterator
      while (eIter.hasNext) {
       val p = eIter.next.asInstanceOf[Product]
       println(p)
      }
    })
  }

  def withTxSession(f:(Session) => Any) = {
    val s = sessionFactory.getCurrentSession
    val t = s.beginTransaction
    val r = f(s)
    t.commit
    r
  }

  lazy val parseDocFactory = javax.xml.parsers.DocumentBuilderFactory.newInstance
  def parseDoc(x: Node) = {
    import org.xml.sax.InputSource
    import java.io.StringReader
    parseDocFactory.newDocumentBuilder.parse(new InputSource(new StringReader(x.toString)))
  }

  def configDoc = parseDoc(configXML)
  def configXML =
  <hibernate-configuration>
    <session-factory>
      <property name="connection.driver_class">org.h2.Driver</property>
      <property name="connection.url">jdbc:h2:tcp://localhost:9092/hibernate</property>
      <property name="connection.username">sa</property>
      <property name="connection.password"></property>
      <property name="dialect">org.hibernate.dialect.H2Dialect</property>
      <property name="current_session_context_class">thread</property>
      <property name="hibernate.hbm2ddl.auto">create</property>
      <property name="hibernate.show_sql">true</property>
        
      <mapping class="etc9.Product"/>
    </session-factory>
  </hibernate-configuration>
}

前と同じ結果が得られる。これで、hibernate.cfg.xmlは削除可能