ORM比較(2) - Hibernate
JavaのORMと言えば、Hibernateと言われるくらい有名なライブラリです。HibernateはJ2EEの標準APIであるJPAに対応しているので、Hibernateをそのまま使う場合とJPA互換の使い方と2通りのデータ取得方法で書いてみます。
公式ページは https://www.hibernate.org/ になってます。
今回使うライブラリは、Hibernate-Core,Hibernate-Annotations,Hibernate-EntityManagerを使うことになります。実際に必要なライブラリは以下の通り。
- antlr-2.7.6.jar
- commons-collections-3.1.jar
- commons-logging-1.1.jar
- dom4j.jar
- ejb3-persistence.jar
- hibernate-annotations.jar
- hibernate-commons-annotations.jar
- hibernate-core.jar
- hibernate-entitymanager.jar
- javaassist.jar
- jta.jar
- log4j-1.2.15.jar
- postgresql-8.3-603.jdbc4.jar
- slf4j-api-1.5.6.jar
- slf4j-log4j12-1.5.6.jar
それでは実際のソースを。
Entityクラスは、クラスにJPAのjavax.persistence.Entityアノテーションを付ければOKです。対応するテーブル名やカラム名などもJPAのアノテーションに従います。非常に細かい設定が可能になります。また、前回のActiveObjectsと違い代替Keyは必要なく javax.persistence.Idアノテーションを付けた列がKeyとなります。
ユーザマスタ(テーブル名はHUser)のEntity
@Entity @Table(name="huser") public class HUser { @Id @Column(name="user_id", unique=true) public String userId; @Column(name="password") public String password; @ManyToOne() @JoinColumn(name="user_group_id") public HUserGroup userGroup; }
ユーザグループ(テーブル名はHUserGroup)のEntity
@Entity @Table(name="huser_group") public class HUserGroup { @Id @Column(name="user_group_id", unique=true) public String userGroupId; @OneToMany(mappedBy="userGroup") public List<HUser> users = new ArrayList<HUser>(); }
コネクションの作成部分はSingletonな実装にしておきます。ここで HibernateのNativeAPIを使うかJPAを使うかで処理が分かれますので、それぞれ別のクラスにしておきます。
まずは、HibernateのNativeAPIを使うクラスです。こちらの設定は、クラスパス内の hibernate.cfg.xmlと言うファイルを探してその内容を使います。
public class HibernateSessionFactory { private static final SessionFactory factory_; static { try { factory_ = new AnnotationConfiguration().configure().buildSessionFactory(); } catch (HibernateException ex) { throw new ExceptionInInitializerError(ex); } } public static Session createSession() { return factory_.openSession(); } }
hibernate.cfg.xmlはこのように記述します。注意点としては、DBの接続設定だけではなく、使用するEntityのクラス名をここに記述する必要があります。
<?xml version="1.0"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">org.postgresql.Driver</property> <property name="hibernate.connection.url">jdbc:postgresql://server:5432/sample_test</property> <property name="hibernate.connection.username">postgres</property> <property name="hibernate.connection.password">postgres</property> <property name="hibernate.connection.pool_size">3</property> <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <mapping package="ch.jpn.taoe.orm_comp.hibernate.entity"/> <mapping class="ch.jpn.taoe.orm_comp.hibernate.entity.HUserGroup"/> <mapping class="ch.jpn.taoe.orm_comp.hibernate.entity.HUser"/> </session-factory> </hibernate-configuration>
JPAのAPIを使うクラスは以下のようになります。設定ファイルは、クラスパス内の META-INF/persistence.xml になります。
public class EntityManagerFactory { private static final javax.persistence.EntityManagerFactory emf_; static { try { emf_ = Persistence.createEntityManagerFactory("HibernateSample"); } catch (Exception ex) { throw new ExceptionInInitializerError(ex); } } public static EntityManager getEntityManager() { return emf_.createEntityManager(); } }
persistence.xmlは以下の通り。実際の設定は、hibernate.cfg.xmlに丸投げしてます。
<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" 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_1_0.xsd"> <persistence-unit name="HibernateSample" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.ejb.cfgfile" value="/hibernate.cfg.xml" /> </properties> </persistence-unit> </persistence>
最後に、実際にORMを使う部分のソースです。まずHibernateのNativeAPIを使う場合のデータの取得は前述のクラスからSessionを取得後に、Session#createCriteria の戻り値に Criteria#list を呼び出すことで全件取得ができます。JPAの場合には、前述のクラスからEntityManagerを取得し、EntityManager#createQueryの引数に JPQLを渡すことでデータの取得ができます。
データのInsertを行う部分は長くなるので省略してあります。最後にソースが公開してありますので、そちらを参照してください。
public class Main { public static void createNativeTestData() { /*省略*/ } public static void createJpaTestData() { /*省略*/ } public static void main(String[] args) { if (false) createNativeTestData(); if (false) createJpaTestData(); System.out.println("Select HibernateNative Query:"); { Session session = HibernateSessionFactory.createSession(); List<HUserGroup> list = session.createCriteria(HUserGroup.class).list(); for (HUserGroup group: list) { System.out.println(group.userGroupId + ":"); for (HUser user: group.users) { System.out.println(" " + user.userId + "/" + user.password); } } session.close(); } System.out.println("Select HibernateJPA Query:"); { EntityManager em = EntityManagerFactory.getEntityManager(); List<HUserGroup> list = em.createQuery("select g from HUserGroup g").getResultList(); for (HUserGroup group: list) { System.out.println(group.userGroupId + ":"); for (HUser user: group.users) { System.out.println(" " + user.userId + "/" + user.password); } } em.close(); } } }
以上です。
上記のソースは、Subversionにて http://taoe.jpn.ch:8080/svn/trunk/orm_compare/Hibernate から取得できます。良かったら自分で動かしてみてください*1。
*1:やっぱりPostgreSQLが必要になります