Top > MyPage
 

Hibernate

ORマッピングが主流となっているJavaワールドの、その中心的な(といっても良いのかな)Hibernateの基本的な使い方を説明します。 といっても、ほんのさわりの部分(それ以外にあまり知らないので(--;)に絞っています。

まずはORマッピングとは何?

一言で言うと、Oがオブジェクト(Javaの)、Rがリレーショナルデータベースですので、「Javaのクラスと データベースのテーブルを結びつけるためのマッピングシステム」ということでしょうか。

これだと今ひとつピンと来ないでしょうから、もう少し具体的に説明します。 詳しくは連載:Hibernateで理解するO/Rマッピング楽々DBプログラミング!O/Rマッピングツール Hibernateなどを見て、勉強してください。

create table USERS (
   ID integer generated by default as identity (start with 1),
   USER_ID varchar(64) not null,
   EMAIL varchar(64) not null,
   MEMBER_NAME varchar(64),
   NOTE varchar(128),
   primary key (ID),
   unique (USER_NAME)
);
                    

というようなデータベースがあったとします。これを次のようなJavaのクラスと関係づけるわけです。

ちょっと長めですが、ほとんどが変数の宣言とsetter,getterからなっています。つまり

    /**
     * ID番号
     */
    private Integer id;

    /**
     * ログイン名
     */
    private String userName;

    /**
     * E-MAIL
     */
    private String email;

    /**
     * 氏名(漢字等可)
     */
    private String MemberName;

    /**
     * 備考
     */
    private String Note;
            

の5つのフィールド(変数)が上記のテーブルのフィールドに対応します。

package com.chikkun.webcms.test;
import java.io.Serializable;
/**
 * @author Chiku Kazuro
 * @version 0.1 ORマッピング用のBean
 */
public class TestBean implements Serializable {
    /**
     * ID番号
     */
    private Integer id;

    /**
     * ログイン名
     */
    private String userName;

    /**
     * E-MAIL
     */
    private String email;

    /**
     * 氏名(漢字等可)
     */
    private String MemberName;

    /**
     * 備考
     */
    private String Note;

    /**
     * @return Returns the email.
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email
     *            The email to set.
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * @return Returns the id.
     */
    public Integer getId() {
        return id;
    }

    /**
     * @param id
     *            The id to set.
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /**
     * @return Returns the memberName.
     */
    public String getMemberName() {
        return MemberName;
    }

    /**
     * @param memberName
     *            The memberName to set.
     */
    public void setMemberName(String memberName) {
        MemberName = memberName;
    }

    /**
     * @return Returns the note.
     */
    public String getNote() {
        return Note;
    }

    /**
     * @param note
     *            The note to set.
     */
    public void setNote(String note) {
        Note = note;
    }

    /**
     * @return Returns the userName.
     */
    public String getUserName() {
        return userName;
    }

    /**
     * @param userName
     *            The userName to set.
     */
    public void setUserName(String userName) {
        this.userName = userName;
    }
}


                    

そして、これらを「結びつけて」、SQL文を直接使わずにデータをインサートしたり、 削除したり、或いは選択したりするというのが、Hibernate(ORマッピングフレームワーク)のお仕事だということになります。

まずは準備

Hibernateのダウンロードと展開

いつものように、Hibernateのダウンロード先にいって、最新のものを ダウンロードし、以前と同様c:/javaに展開します。ここで、せっかく3.05という新しいバージョンも出ていることだし、 と思って、色々試したのですが(数時間すったもんだやった)、うまくいかないので、Hibernateの全リストから hibernate-2.1.8.tar.gz hibernate-extensions-2.1.3.tar.gzをダウンロードして、 c:/java以下に展開します。

build.xmlの準備

本来は手作業でやった方が色々覚えるのでしょうが、時間もないことだし、またもやxdocletを使って必要なファイルを 自動で作ろうと思います。それには今までのbuild.xmlに書き加える必要があります。以下の<!--added start-->から<!-- added end-->の間が書き加えた箇所です。

<?xml version="1.0" encoding="Windows-31J"?>
<project name="webcms" default="struts">
    <!-- define properties. -->
    <property file="./build.properties"/>
    <property name="src.dir" value="WEB-INF/src"/>
    <property name="merge.dir" value="WEB-INF/merge"/>
    <property name="web.dir" value="."/>
    <property name="conf.dir" value="WEB-INF/conf"/>
    <property name="javadocs.dir" value="${docs.dir}/api"/>
    <property name="classes.dir" value="WEB-INF/classes"/>
    <property name="target.resources" value="WEB-INF/classes/Resources"/>
    <property name="config.resources" value="conf"/>
    <property name="local.encoding" value="Windows-31J"/>
    <!--added start-->
    <fileset id="hibernate.jar" file="${HIBERNATE_HOME}/hibernate2.jar"/>
    <fileset id="hibernate.extension" file="${HIBERNATE_EXTENSION_HOME}/hibernate-tools.jar"/>
    <fileset id="hibernate.libs" dir="${HIBERNATE_HOME}/lib">
        <include name="*.jar"/>
    </fileset>
    <fileset id="hsql.jar" file="${HSQLDB}/lib/hsqldb.jar"/>
    <!-- added end-->
    <!-- define library filesets. -->
    <fileset id="struts.libs" dir="WEB-INF/lib">
        <include name="struts.jar"/>
    </fileset>
    <fileset id="servlet.jar" file="${CATALINA_HOME}/common/lib/servlet-api.jar"/>
    <fileset id="xdoclet.libs" dir="${XDOCLET_HOME}/lib">
        <include name="*.jar"/>
    </fileset>
    <!-- define build classpath. -->
    <path id="build.classpath">
        <pathelement path="${classes.dir}"/>
        <fileset refid="struts.libs"/>
        <fileset refid="xdoclet.libs"/>
        <fileset refid="servlet.jar"/>
        <!--added start-->
        <fileset refid="hibernate.jar"/>
        <fileset refid="hsql.jar"/>
        <fileset refid="hibernate.extension"/>
        <fileset refid="hibernate.libs"/>
        <!-- added end-->
    </path>
    <!-- define targets. -->
    <target name="clean">
        <delete dir="${classes.dir}"/>
        <delete dir="${dist.dir}"/>
        <delete dir="${javadocs.dir}"/>
    </target>
    <!--added start-->
    <target name="hibernate">
        <copy todir="${classes.dir}" filtering="no" overwrite="yes">
            <fileset dir="${conf.dir}" includes="hibernate.cfg.xml"/>
        </copy>
        <property name="projct.home" value="${PROJECT_HOME}"/>
        <property name="database" value="${DATABASE}"/>
        <replace file="${classes.dir}/hibernate.cfg.xml" value="${database}" token="@DATABASE@"/>
        <taskdef name="xdoclet" classname="xdoclet.modules.hibernate.HibernateDocletTask">
            <classpath refid="build.classpath"/>
        </taskdef>
        <xdoclet destdir="${classes.dir}" excludedtags="@version,@author,@param,@return"
            force="false" mergedir="WEB-INF/merge" verbose="false" encoding="${local.encoding}">
            <fileset dir="${src.dir}">
                <include name="**/*.java"/>
            </fileset>
            <hibernate version="2.0"/>
        </xdoclet>
    </target>
    <target name="schemaexport" depends="hibernate">
        <taskdef name="schemaexport" classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask"
            classpathref="build.classpath"/>
        <schemaexport config="WEB-INF/classes/hibernate.cfg.xml" quiet="no" text="no" drop="no"
            delimiter=";" output="schema-export.sql"/>
    </target>
    <!-- added end-->
    <target name="struts" depends="property">
        <taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask"
            classpathref="build.classpath"/>
        <webdoclet destdir="${src.dir}" mergedir="${merge.dir}"
            excludedtags="@version,@author,@todo,@param" force="true" verbose="true"
            encoding="${local.encoding}">
            <fileset dir="${src.dir}">
                <include name="**/*.java"/>
            </fileset>
            <strutsconfigxml version="1.2" destdir="WEB-INF" xmlencoding="Windows-31J"/>
            <strutsvalidationxml destdir="WEB-INF"/>
        </webdoclet>
    </target>
    <target name="web" depends="struts">
        <taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask"
            classpathref="build.classpath"/>
        <webdoclet destdir="WEB-INF/src" mergedir="WEB-INF/merge"
            excludedtags="@version,@author,@todo" force="true" verbose="false"
            encoding="${local.encoding}">
            <fileset dir="WEB-INF/src">
                <include name="**/*.java"/>
            </fileset>
            <deploymentdescriptor servletspec="2.3" destdir="WEB-INF"/>
            <strutsconfigxml version="1.2" destdir="WEB-INF"/>
            <strutsvalidationxml destdir="WEB-INF"/>
        </webdoclet>
        <fixcrlf srcdir="WEB-INF" cr="remove" includes="*.xml"
            excludes="tiles-defs.xml,holidays.xml,equipment.xml"/>
    </target>
    <target name="property">
        <delete failonerror="false">
            <fileset dir="${target.resources}" includes="ApplicationResources.properties"/>
        </delete>
        <native2ascii encoding="${local.encoding}" src="${config.resources}"
            dest="${target.resources}" includes="ApplicationResources.properties"/>
    </target>
</project>

                        

次にこれに伴い、build.propertiesにも書き加えます。

ARCHIVE_DIR=c:/java
PROJECT_HOME=c:/eclipse/workspace/webcms
XDOCLET_HOME=${ARCHIVE_DIR}/xdoclet-1.2.2
CATALINA_HOME=c:/Tomcat 5.0

#added start
HIBERNATE_HOME=${ARCHIVE_DIR}/hibernate-2.1
HIBERNATE_EXTENSION_HOME=${ARCHIVE_DIR}/hibernate-extensions-2.1.3/tools
DATABASE=jdbc:hsqldb:file://${PROJECT_HOME}/WEB-INF/database/webcms
HSQLDB=${ARCHIVE_DIR}/hsqldb
#added end
                        

さらに、次のようなhibernate.cfg.xmlWEB-INF/confディレクトリーに作ります。


<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
  "-//Hibernate/Hibernate Configuration DTD 2.0//EN"
  "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="dialect">net.sf.hibernate.dialect.HSQLDialect</property>
        <property name="show_sql">false</property>
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="connection.url">@DATABASE@</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"/>
        <!--this define-->
        <mapping resource="com/chikkun/webcms/test/TestBean.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
                        

これはHibernateを使う際のデータベース等の設定と、マッピングするクラスがどこに所在するかを指定しています。特に下の箇所は マッピングするテーブルが増えれば、書き加えていく必要があります。

        <!--this define-->
        <mapping resource="com/chikkun/webcms/test/TestBean.hbm.xml"/>
                        

また、@DATABASE@という部分はbuild.properties の中の、DATABASEという部分を使って、さらにbuild.xmlの中の以下の部分で置き換えています。

        <property name="projct.home" value="${PROJECT_HOME}"/>
        <property name="database" value="${DATABASE}"/>
        <replace file="${classes.dir}/hibernate.cfg.xml" value="${database}" token="@DATABASE@"/>
                        

これで、下準備は終了。次に、xdocletのタグを付けていきます。

TestBeanにxdocletのタグを書き加える

さて、上の方で書いた、TestBean.javaにxdocletのhibernate用のタグを書き加えたものが、 以下のようです。

/*
 * Created on 2005/06/03
 *
 */
package com.chikkun.webcms.test;

import java.io.Serializable;

/**
 * @author Chiku Kazuro
 * @version 0.1 ORマッピング用のBean
 * @hibernate.class table="USERS"
 *  
 */
public class TestBean implements Serializable {
    /*
     * create table USERS ( ID integer generated by default as identity (start
     * with 1), USER_ID varchar(64) not null, EMAIL varchar(64) not null,
     * MEMBER_NAME varchar(64), NOTE varchar(64), primary key (ID), unique
     * (USER_NAME) );
     */

    /**
     * ID番号
     */
    private Integer id;

    /**
     * ログイン名
     */
    private String userName;

    /**
     * E-MAIL
     */
    private String email;

    /**
     * 氏名(漢字等可)
     */
    private String MemberName;

    /**
     * 備考
     */
    private String Note;

    /**
     * @return Returns the email.
     * @hibernate.property column="EMAIL" length="64" not-null="true"
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email
     *            The email to set.
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * @return Returns the id.
     * @hibernate.id column="ID" generator-class="native"
     */
    public Integer getId() {
        return id;
    }

    /**
     * @param id
     *            The id to set.
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /**
     * @return Returns the memberName.
     *            The memberName to set.
     * @hibernate.property column="MEMBER_NAME" length="64"
     *            not-null="false"
     *     */
    public String getMemberName() {
        return MemberName;
    }

    /**
     * @param memberName
     */
    public void setMemberName(String memberName) {
        MemberName = memberName;
    }

    /**
     * @return Returns the note.
     * @hibernate.property column="NOTE" length="128" not-null="false"
     */
    public String getNote() {
        return Note;
    }

    /**
     * @param note
     *            The note to set.
     */
    public void setNote(String note) {
        Note = note;
    }

    /**
     * @return Returns the userName.
     * @hibernate.property column="USER_NAME" length="64" not-null="true"
     *                     unique="true"
     */
    public String getUserName() {
        return userName;
    }

    /**
     * @param userName
     *            The userName to set.
     */
    public void setUserName(String userName) {
        this.userName = userName;
    }
}


                    ! 

@hibernate.class@hibernate.propertyというようなものがそれです。読めばだいたいわかると思います。getterの上に テーブルのフィールドを表すxdocletのタグを書くということに留意してください。

antの実行

さて、これでhibernate用の設定ファイルを作成する準備が出来ました。早速antを実行しましょう。

ant hibernateを実行すると、そのhibernate用の設定ファイルが出来、

ant schemaexportを事項すると、上記の設定ファイルを作成するとともに、HSQLDBのテーブルの定義 までやってしまいます。ちなみにこれを実行して(もしすでにWEB-INF/database/webcms*にファイルがあったら削除しておき)、 新しいファイルが出来たらここまではOKです。

それで、できあがったWEB-INF/classes/hibernate.cfg.xmlWEB-INF/classes/com/chikkun/webcms/test/TestBean.hbm.xml はそれぞれ以下のようになっているはずです。

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

<hibernate-configuration>
  <session-factory>
    <property name="dialect">net.sf.hibernate.dialect.HSQLDialect</property>
    <property name="show_sql">false</property>
    <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property name="connection.url">jdbc:hsqldb:file://c:/eclipse/workspace/webcms/WEB-INF/database/webcms</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"></property>

    <!--this define-->
    <mapping resource="com/chikkun/webcms/test/TestBean.hbm.xml"/>

  </session-factory>
</hibernate-configuration>
                    

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping
>
    <class
        name="com.chikkun.webcms.test.TestBean"
        table="USERS"
        dynamic-update="false"
        dynamic-insert="false"
        select-before-update="false"
        optimistic-lock="version"
    >

        <id
            name="id"
            column="ID"
            type="java.lang.Integer"
        >
            <generator class="native">
              <!--  
                  To add non XDoclet generator parameters, create a file named 
                  hibernate-generator-params-TestBean.xml 
                  containing the additional parameters and place it in your merge dir. 
              --> 
            </generator>
        </id>

        <property
            name="email"
            type="java.lang.String"
            update="true"
            insert="true"
            access="property"
            column="EMAIL"
            length="64"
            not-null="true"
        />

        <property
            name="note"
            type="java.lang.String"
            update="true"
            insert="true"
            access="property"
            column="NOTE"
            length="128"
            not-null="false"
        />

        <property
            name="userName"
            type="java.lang.String"
            update="true"
            insert="true"
            access="property"
            column="USER_NAME"
            length="64"
            not-null="true"
            unique="true"
        />

        <!--
            To add non XDoclet property mappings, create a file named
                hibernate-properties-TestBean.xml
            containing the additional properties and place it in your merge dir.
        -->

    </class>

</hibernate-mapping>

                    

です。さあ、あとはこれを使ってデータをインサートしたり、deleteしたりします。

DAOの作成

さて、準備は万端となりましたので、これからデータをインサートします。ところで、DAOとは「Data Access Object」ということで、 データベースのデータにアクセスするためのオブジェクトということ。

それにはある程度、hibernateのイディオムが必要です。基本的には、session(Httpのsessionじゃありません)というインスタンスを利用して、hibernate はデータの管理をします。

     Configuration config = new Configuration().configure(); // 設定の読み込み
    // セッションファクトリーの作成
    SessionFactory sessionfactory = config.buildSessionFactory();
    // セッションオープン
    Session session = sessionfactory.openSession();
    List list = session.find(" FROM WorkGroup "); //検索処理の実行
                    

という感じで、Sessionオブジェクトを取得し、このSessionを使って、上記のような検索を実行します。しかし、毎回セッションを取得するというようなことを 書くのは面倒なので、継承を使って少々楽をしましょう(パッケージは本来は別にするべきでしょうが、話しを単純にするために、作成も楽にするために全て同じものにしています)。

次のようなスーパークラスを作成します。そして、実際のDAOはそれをextendsして作成します。まずはBaseDAO.java。

/*
 * Created on 2005/06/03
 *
 */
package com.chikkun.webcms.test;

import java.util.List;

import net.sf.hibernate.Criteria;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.expression.Example;
import net.sf.hibernate.expression.Expression;
import net.sf.hibernate.expression.Order;

/**
 * @author Chiku Kazuro
 * @version 0.1
 *  
 */
public class UserDAO extends BaseDAO {

    public void save(TestBean u) {
        Session session = null;
        Transaction transaction = null;
        try {
            session = getSession();
            transaction = session.beginTransaction();
            session.save(u);
            transaction.commit();
            //hsqlCleanup(session);//これを使うとスピードが遅くなるかも
        } catch (Exception ex) {
            System.out.println("データベースエラー:" + ex.getMessage());
            if (transaction != null) {
                try {
                    transaction.rollback();
                } catch (HibernateException ignore) {
                }
            }
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (Exception ignore) {
                }
            }
        }
    }

    private void hsqlCleanup(Session s) {
        try {
            s.connection().createStatement().execute("checkpoint");
        } catch (Exception e) {
            System.out.println("データベースエラー:" + e.getMessage());
        }
    }

    public void delete(TestBean u) {
        Session session = null;
        Transaction transaction = null;
        try {
            session = getSession();
            transaction = session.beginTransaction();
            session.delete(u);
            transaction.commit();
            session.flush();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());

            if (transaction != null) {
                try {
                    transaction.rollback();
                } catch (HibernateException ignore) {
                }
            }
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }
    }

    public void delete(String userName) {
        Session session = null;
        Transaction transaction = null;
        try {
            session = getSession();
            transaction = session.beginTransaction();
            session.delete("FROM TestBean as bean where bean.userName = ?",
                    userName, Hibernate.STRING);
            transaction.commit();
            session.flush();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());

            if (transaction != null) {
                try {
                    transaction.rollback();
                } catch (HibernateException ignore) {
                }
            }
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }
    }

    public void deleteAll() {
        Session session = null;
        Transaction transaction = null;
        try {
            session = getSession();
            transaction = session.beginTransaction();
            session.delete("FROM TestBean");
            transaction.commit();
            session.flush();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());

            if (transaction != null) {
                try {
                    transaction.rollback();
                } catch (HibernateException ignore) {
                }
            }
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }
    }

    public void update(TestBean u) {
        Session session = null;
        Transaction transaction = null;
        try {
            session = getSession();
            transaction = session.beginTransaction();
            session.update(u);
            transaction.commit();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());
            if (transaction != null) {
                try {
                    transaction.rollback();
                } catch (HibernateException ignore) {
                }
            }
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }
    }

    public List findAll() {
        Session session = null;
        try {
            session = getSession();
            Query query = session.createQuery("FROM TestBean");

            return query.list();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }
    }

    public List findById(Integer id) {
        List result = null;
        Session session = null;
        try {
            session = getSession();
            Criteria criteria = session.createCriteria(TestBean.class);
            if (id != null && id.intValue() > 0) {
                criteria.add(Expression.eq("id", id));
            }
            result = criteria.list();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());

            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }
        return result;
    }

    public List findByLoginId(String id) {
        List result = null;
        Session session = null;
        try {
            session = getSession();
            Criteria criteria = session.createCriteria(TestBean.class);
            if (id != null && !"".equals(id)) {
                criteria.add(Expression.eq("userName", id));//テーブルのフィールド名じゃない
            }
            result = criteria.list();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());

            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }
        return result;
    }

    public List findByQBE(TestBean bean) {

        List result = null;
        Session session = null;
        try {
            session = getSession();
            Example example = Example.create(bean);
            Criteria criteria = session.createCriteria(TestBean.class);
            criteria.add(example);
            result = criteria.list();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());

            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }
        return result;

    }

    public List findSortedByUserNameHQL() {
        Session session = null;
        try {
            session = getSession();
            Query query = session
                    .createQuery("FROM TestBean order by USER_NAME");

            return query.list();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }

    }

    public List findSortedByUserNameCriteria() {
        Session session = null;
        List result = null;
        try {
            session = getSession();
            Criteria criteria = session.createCriteria(TestBean.class);
            ;
            criteria.addOrder(Order.desc("userName"));
            result = criteria.list();
            return result;
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }

    }

    public Integer getLastId() {
        Session session = null;
        try {
            session = getSession();
            Query query = session.createQuery("FROM TestBean order by ID");

            List list = query.list();
            int last = list.size() - 1;
            TestBean bean = (TestBean) list.get(last);
            return bean.getId();
        } catch (HibernateException ex) {
            System.out.println("データベースエラー:" + ex.getMessage());
            throw new RuntimeException(ex.getMessage());
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (HibernateException ignore) {
                }
            }
        }

    }
}

                    

そして、上記のDAOを使って、データの出し入れをやってみましょう。今回はstrutsのActionを作るのは面倒なので、通常のJavaの アプリケーション、mainメソッドを持つもので、さあ作ってみましょう。そうそうその前にhibernateに必要なjarファイルを、c:/java/hibernate-2.1/lib からコピーしておかなきゃならない。バージョンはともかく、あるものはそのままにして、ないものはコピーし、さらにeclipseのビルドパスに加えます。

  1. hibernate2.jar
  2. commons-logging-1.0.3.jar(これは既にある)
  3. commons-collections-2.1.jar(これは既にある)
  4. commons-lang-1.0.1.jar(これは既にある)
  5. cglib-2.0-rc2.jar
  6. dom4j-1.4.jar
  7. jta.jar
  8. ehcache-0.6.jar
  9. odmg-3.0.jar
  10. xml-apis.jar
  11. xerces-2.4.0.jar
  12. xalan-2.4.0.jar

上記の設定が終わったら、mainメソッドを持つソースを実際書きましょう。そうそう、その際上記にあったant schemaexportでデータベースを初期化しておきましょう。 このときに注意1。schmaexportした直後に、データの出し入れをするJavaを実行するとエラーが起こる可能性があります。これはデータベースがlockをかけて、それが解放されていないからです。 15秒ほど待ってから、実行しましょう。さて、ソースは・・・(ソースを読みながらHibernateについてわからない場合はHibernateのJavaDocを見てください)。 また、HibernateにはデータベースとのやりとにりHQLやらcriteriaなどがありますが、今回はそれらをわざと混ぜて使っているので、その辺もご注目(それらは上記のソース---DAO)を!

/*
 * Created on 2005/06/04
 *
 */
package com.chikkun.webcms.test;

import java.util.Iterator;
import java.util.List;

/**
 * @author Chiku Kazuro
 * @version 0.1
 *
 */
public class TestDataBaseMain {

    public static void main(String[] args) {
        //1人目
        UserDAO ud = new UserDAO();
        TestBean tb = new TestBean();
        tb.setUserName("chikkun");
        tb.setEmail("chikkun@chikkun.com");
        tb.setMemberName("知久和郎");
        tb.setNote("もう12時半だよ");
        //idは自動でhibernateが入れてくれるのでsetId()は必要ない。
        ud.save(tb);

        System.out.println(tb.getUserName() + "をインサートしました!");

        //2人目
        tb = new TestBean();
        tb.setUserName("denn");
        tb.setEmail("denn@chikkun.com");
        tb.setMemberName("伝法谷千代春");
        tb.setNote("だいたい、天智天皇は暗殺されたんだよ!");
        ud.save(tb);

        System.out.println(tb.getUserName() + "をインサートしました!");

        //3人目
        tb = new TestBean();
        tb.setUserName("terui");
        tb.setEmail("terui@chikkun.com");
        tb.setMemberName("照井大王");
        tb.setNote("遊ぶ暇がない");
        ud.save(tb);

        System.out.println(tb.getUserName() + "をインサートしました!");

        //4人目
        tb = new TestBean();
        tb.setUserName("manabu");
        tb.setEmail("manabu@chikkun.com");
        tb.setMemberName("学くん");
        tb.setNote("回路図を持ってきて!");
        ud.save(tb);
        System.out.println(tb.getUserName() + "をインサートしました!");

        //検索開始

        //人数取得
        List list = ud.findAll();
        System.out.println("現在データ数は" + list.size() + "です。");

        //最後のIDの人を取得
        Integer last = ud.getLastId();
        list = ud.findById(last);
        System.out.println("データベースの" + last.intValue() + "番目(最後)の人は"
                + ((TestBean) list.get(0)).getMemberName() + "さんです。");

        //dennを検索
        list = ud.findByLoginId("denn");
        System.out.println("dennさんの実名は"
                + ((TestBean) list.get(0)).getMemberName() + "さんです。");

        //chikkunをTestBeanで取得
        tb = new TestBean();
        tb.setUserName("chikkun");
        list = ud.findByQBE(tb);
        System.out.println("オブジェクトでも検索できる:この人の実名は"
                + ((TestBean) list.get(0)).getMemberName() + "さんです。");

        //userNameでソートした全データを取得、表示(HQLを利用して)
        list = ud.findSortedByUserNameHQL();
        Iterator it = list.iterator();
        System.out.println("\nSorted by userName with HQL");
        int i = 0;
        while (it.hasNext()) {
            i++;
            TestBean sorted = (TestBean) it.next();
            System.out.println(i + "番目の人は" + sorted.getUserName() + "です。");
        }

        //userNameで降順ソートした全データを取得、表示(Criteriaを利用して)
        list = ud.findSortedByUserNameCriteria();
        it = list.iterator();
        System.out.println("\nSorted by userName with Criteria(降順)");
        i = 0;
        while (it.hasNext()) {
            i++;
            TestBean sorted = (TestBean) it.next();
            System.out.println(i + "番目の人は" + sorted.getUserName() + "です。");
        }

        //chikkunのuserNameを使って削除
        ud.delete("chikkun");
        list = ud.findAll();
        System.out.println("\ndelete by userName with HQL(userName直接指定)");
        System.out.println("chikkunを削除しました。現在データ数は" + list.size() + "です。");

        //dennの検索したTestBeanを使っての削除
        list = ud.findByLoginId("denn");
        TestBean deleteBean = (TestBean) list.get(0);
        ud.delete(deleteBean);
        list = ud.findAll();
        System.out.println("\ndelete by TestBean with HQL(TestBeanオブジェクトで指定)");
        System.out.println("dennを削除しました。現在データ数は" + list.size() + "です。");

        //managuのmemberNameの更新
        list = ud.findByLoginId("manabu");
        TestBean updateBean = (TestBean) list.get(0);
        updateBean.setMemberName("鈴木学(僕の同級生)");
        ud.delete(updateBean);
        System.out.println("\nupdate memberName with HQL");
        System.out.println("manabuの氏名を、養子縁組のために、変更しました(それ俺?)。佐藤学 -> "
                + updateBean.getMemberName() + " になりました。");

        //全データの削除
        ud.deleteAll();
        list = ud.findAll();
        System.out.println("\nそして、誰もいなくなりました。");
        System.out.println("dennを削除しました。現在データ数は" + list.size() + "です。");

        //おしまい
    }
}

                    

これを実行すると、次のような出力が(コンソールに)あるはずです。

chikkunをインサートしました!
dennをインサートしました!
teruiをインサートしました!
manabuをインサートしました!
現在データ数は4です。
データベースの12番目(最後)の人は学くんさんです。
dennさんの実名は伝法谷千代春さんです。
オブジェクトでも検索できる:この人の実名は知久和郎さんです。

Sorted by userName with HQL
1番目の人はchikkunです。
2番目の人はdennです。
3番目の人はmanabuです。
4番目の人はteruiです。

Sorted by userName with Criteria(降順)
1番目の人はteruiです。
2番目の人はmanabuです。
3番目の人はdennです。
4番目の人はchikkunです。

delete by userName with HQL(userName直接指定)
chikkunを削除しました。現在データ数は3です。

delete by TestBean with HQL(TestBeanオブジェクトで指定)
dennを削除しました。現在データ数は2です。

update memberName with HQL
manabuの氏名を、養子縁組のために、変更しました(それ俺?)。佐藤学 -> 鈴木学 になりました。

そして、誰もいなくなりました。
dennを削除しました。現在データ数は0です。
                    

上記が出力されたら、めでたしめでたし。

これだけじゃない

Hibernateの実力はこんなもんじゃない。というか、かつては私自身もそうだったのですが、この程度ならSQL文を 直に扱っても「大して変わらないじゃん」てな話しになります。しかし、実際には次のようなメリット(全てを把握していませんが)があります。

  1. オブジェクト指向とSQL文というように、頭を切り換える必要がない。
  2. Beanを基本にデータを扱っている上で、それを自動でsetしてくれるので、コーディングが楽。
  3. ここには例としてあげませんでしたが、テーブルが親と子というような関係にあった場合、親を検索すると、それに伴い 自動で子供も自動で取得できる。
  4. データベースを変更するという状況になっても、hibernate.cfg.xmljdbc:hsqldb:file://c:/eclipse/workspace/webcms/WEB-INF/database/webcms を変更するだけでよいし、データベースごとの方言なども吸収してくれる。

などなど色々あると思います。

おしまい!!!

by 知久和郎