1. | S2Hibernateの概要 S2Hibernateリファレンス セットアップ 基本的な使い方 JavaBeans Dao(Data Access Object) diconファイル S2hibernate.daoの使い方 JavaBeans Dao(Data Access Object) diconファイル example 基本的な使い方の例 S2hibernate.daoの使い方の例 OpenSessionInViewの使い方 ## S2Hibernateの概要 S2Hibernateは以下の特徴を持っています。 S2のJTAやConnectionPoolとHibernateが簡単に連動するようになります。 これまでHibernateで開発するときの悩みの種だったSession管理をS2Hibernateが自動的に行ってくれるので、 開発者はSessionのオープン・クローズ、Transaction処理から開放されます。 SessionはJTAのトランザクション中は維持され、トランザクションの終了時に自動的にクローズ(flushも)されます。 HibernateのSessionを意識しないで記述できる S2Hibernate.daoを使うことで、HibernateのSessionを意識せずにDaoを記述できるようになります。 S2hibernate.daoでは定数アノテーションという技術を使い、ソースコードにメタデータを記述するだけで動作するようになります。 定数アノテーションとHQL文だけを書けば、動作するようになるので開発効率が向上します。 ## S2Hibernateリファレンス ### セットアップ ソースのインポート S2と同様にJDK1.4以上が必要です。S2HibernateVx.x.x.jarを解凍してできたS2hibernateディレクトリをEclipseのJavaプロジェクトとして丸ごとインポートしてください。.classpathを上書きするか聞かれるので、すべてはいのボタンをクリックして、すべてを取り込みます。 これで、私と全く同じ環境になります。src/examples配下にサンプルもあります。 必要なjarファイル S2Hibernateとして必要なjarファイルは、s2hibernate/libにそろってます。Hibernateはコネクションプールやキャッシュの実装をいろいろ選べるようになっているので、S2Hibernateで用意していない実装が必要な場合は、Hibernateのサイトよりダウンロードしてください。 クラスパス libのjarファイル(hsqldb.jar以外)とsrcのhibernate.cfg.xml、ehcache.xml、j2ee.dicon、log4j.propertiesをCLASSPATHにとおせば、S2Hibernateを実行できます。Eclipseにインポートして使う場合は設定は不要です。 データベース 簡単に機能を試すことができるように、RDBMSとしてHSQLDBを用意しています。機能を試す前にあらかじめHSQLDBを実行しておいてください。HSQLDBを実行するには、bin/runHsqldb.batをダブルクリック(Windowsの場合)します。lib/hsqldb.jarはHSQLDBを実行する上では必要ですが、本番では必要ありません。 ### 基本的な使い方 S2Hibernateの機能を使用するにあたり、JavaBeans、Dao(.java)、diconファイルの作成が必要になります。 #### JavaBeans 通常のJavaBeanを作成します。S2Hibernateを意識する必要はありませが、Hibernateで利用できるように記述してください。 ##### Dao(Data Access Object) 例）Dao実装(EmployeeDaoImpl.java) S2SessionFactory型のフィールドを定義。
       private S2SessionFactory sessionFactory_;
2. コンストラクタあるいはプロパティ経由で実装クラス(S2SessionFactoryImpl)を受け取るように記述。
       public EmployeeDaoImpl(S2SessionFactory sessionFactory) {
       	sessionFactory_ = sessionFactory;
       }
各メソッドでS2SessionFactoryからS2Sessionを取得し、処理を記述する。
    public Employee getEmployee(int empno) {
        List result = sessionFactory_.getSession().find(
            HQL, new Integer(empno), Hibernate.INTEGER);
        if (result.size() > 0) {
            return (Employee) result.get(0);
        } else {
            return null;
        }
    }
- Sessionのオープン・クローズ、トランザクション制御は必要ありません。 S2SessionFactory.getSession()が返すオブジェクトは、HibernateのSessionのラッパーであるS2Sessionです。 実行できるメソッドはHibernateのSessionと同じで、検査例外(HibernateException)を実行時例外(HibernateRuntimeException)に変換してくれます。 そのため、HibernateExceptionをcatchしたくないクラスは特に何もする必要はありません。 catchする必要がある場合は、HibernateRuntimeExceptionでcatchしてgetCause()でHibernateExceptionを取り出します。 #### diconファイル 作成したDaoクラスとorg.seasar.hibernate.impl.S2SessionFactoryImplを追加します。 例）Employee.dicon ### S2Hibernate.daoの使い方 S2hibernate.daoを使うと、Sessionを意識せずにDaoを記述することができます。 S2hibernate.daoでは定数アノテーションという技術を使い、ソースコードにメタデータを記述するだけで動作するようになります。 定数アノテーションとHQL文だけを書けば、動作するようになるので開発効率が向上します。 S2Hibernate.daoの機能を使用するにあたり、JavaBeans、Dao(.java)、diconファイルの作成が必要になります。 ##### JavaBeans 通常のJavaBeanを作成します。S2Hibernateを意識する必要はありませが、Hibernateで利用できるように記述してください。 ##### Dao(Data Access Object) S2hibernate.daoでは定数アノテーションという技術を使い、ソースコードにメタデータを記述するだけで動作するようになります。 ###### Daoメタデータ BEANアノテーション Dao(Data Access Object)がどのJavaBeans(エンティティ)に関連付けられているのかはBEANアノテーションで指定します。 例えば、EmployeeDaoクラスがEmployeeエンティティに関連付けられる場合は次のように定義します。
      public static final Class BEAN = Employee.class;
- ARGSアノテーション メソッドの引数名をARGSアノテーションを使って指定します。メソッドの引数名は、リフレクションで取得できないためです。
      public static final String getEmployee_ARGS = "empno";
      public Employee getEmployee(int empno)
  引数が複数ある場合には、カンマで区切ります。 ※ARGSアノテーションを使っての検索の自動処理 S2hibernate.daoに自動的に検索処理を生成させることもできます。HQLアノテーションを指定せず、ARGSアノテーションを指定することで自動的に処理されます。 必要なのは次の定義だけです。
      public static final String getEmployeeByJobDeptno_ARGS = "job, deptno";
      public List getEmployeeByJobDeptno(String job, Integer deptno);
  上の例の場合、次のHQL文として扱い":job",":empno"の部分に引数の値を渡します。
      from Employee emp where emp.job = :job and emp.deptno = :deptno
  S2hibernate.daoでは、引数がNullの場合、検索条件に含めません。この例で、deptnoがNullの場合の次の様なHQLに相当する処理を生成します
      from Employee emp where emp.job = :job
  ※予約語 HQLアノテーション又は、NamedQueryを利用した検索を行う場合、ARGSアノテーションで次の２つが予約語なります。 "firstResult"：検索結果の何レコード目から取得するか。 "maxResults"：検索結果から、何件取得するか。
      public String getEmployeeList_ARGS = "MaxResults";
      public String getEmployeeList_HQL = "from Employee emp order by emp.empno";
      public List getEmployeeList(int MaxResults);
- HQLアノテーション HQLアノテーションを使って、HQL文を指定して実行することができます。
      	public String getEmployeeByJobDeptno_ARGS = "job, deptno";
      	public List getEmployeeByJobDeptno(String job, short deptno);
ARGSアノテーションに合わせて、HQLに値を渡していきます。 ###### メソッドの命名規則 S2Hibernate.daoではメソッドのsignatureより処理を自動的に決定しています。 そのためメソッドのsignatureはS2hibetnate.daoの想定にあわせてもらう必要があります。
処理 | メソッド名 | 備考
save | reate,insert,add ではじまる | 戻り値はvoidです。 引数の型はエンティティの型と一致させます。
update | update,modify,store ではじまる | 戻り値はvoidです。 引数の型はエンティティの型と一致させます。
saveOrUpdate | saveOrUpdateではじまる | 戻り値はvoidです。 引数の型はエンティティの型と一致させます。
load | loadではじまる | 戻り値はObjectです。 引数の型は主キーカラム（id）の型と一致させます。
delete | delete,removeではじまる | 戻り値はvoidです。 引数の型はエンティティの型と一致させます。
select | 上記に該当しない場合 | ・戻り値の型がjava.util.Listを実装している場合、検索結果のエンティティのリストを返します。 ・戻り値の型がエンティティの型の場合、エンティティを返します。 ・それ以外の場合、select count(emp) from Employee empのように1行で1のカラムの値を返すというようにS2Hibernate.daoは想定します。
※select時に実行するHQL文の優先順位 HQLアノテーションを指定している場合、HQLアノテーションに記述したHQL文を実行します。 Hibernateのマッピングファイルに[ Daoインターフェース名 + "_" +メソッド名 ] でNamedQueryが指定されていた場合、その指定されているクエリーを実行します。 Hibernateのマッピングファイルに[ メソッド名 ] でNamedQueryが指定されていた場合、その指定されているクエリーを実行します。 上記に当てはまらない場合、ARGSアノテーションを使って自動処理を行います。 ARGSアノテーションの指定がない場合、BEANアノテーションで指定したエンティティすべてを含んだListを返します。 #### diconファイル 作成したDaoクラスを追加します。 s2hinernate.diconを追加します。 例）EmployeeAutoDao.dicon s2hibernate.dicon ### Example #### 基本的な使い方の例 作成するファイは以下のとおりです。 JavaBean(Employee.java) Hibernateのマッピングファイル(Employee.hbm.xml) Daoインターフェース(EmployeeDao.java) Dao実装(EmployeeDaoImpl.java) diconファイル(Employee.dicon) 実行クラス(EmployeeClient.java) 実行結果 ##### Employee.java 通常のJavaBeanを作成します。S2Hibernateを意識する必要はありませがHibernateで利用できるように記述してください。
    package examples.hibernate.entity;

    import java.io.Serializable;

    public class Employee implements Serializable {

        private long empno;
        private String ename;
        private String job;
        private Short mgr;
        private java.util.Date hiredate;
        private Float sal;
        private Float comm;
        private short deptno;

        public Employee() {}
        public Employee(long empno) { this.empno = empno; }

        public long getEmpno() { return this.empno; }
        public void setEmpno(long empno) { this.empno = empno; }

        public java.lang.String getEname() { return this.ename; }
        public void setEname(java.lang.String ename) { this.ename = ename; }

        public java.lang.String getJob() { return this.job; }
        public void setJob(java.lang.String job) { this.job = job; }

        public Short getMgr() { return this.mgr; }
        public void setMgr(Short mgr) { this.mgr = mgr; }

        public java.util.Date getHiredate() { return this.hiredate; }
        public void setHiredate(java.util.Date hiredate) { this.hiredate = hiredate; }

        public Float getSal() { return this.sal; }
        public void setSal(Float sal) { this.sal = sal; }

        public Float getComm() { return this.comm; }
        public void setComm(Float comm) { this.comm = comm;}

        public short getDeptno() { return this.deptno; }
        public void setDeptno(short deptno) { this.deptno = deptno; }

        public boolean equals(Object other) {
            if ( !(other instanceof Employee) ) return false;
            Employee castOther = (Employee) other;
            return this.getEmpno() == castOther.getEmpno();
        }

        public int hashCode() {
            return (int) this.getEmpno();
        }
    }
##### Employee.hbm.xml 通常のHibernateのマッピングファイルを作成します。S2Hibernateを意識する必要はありません。
    <hibernate-mapping>
        <class name="examples.hibernate.entity.Employee" table="EMP">
            <id name="empno" column="EMPNO" type="long">
                <generator class="assigned"/>
            </id>
            <property name="ename" column="ENAME" type="string" length="10"/>
            <property name="job" column="JOB" type="string" length="9"/>
            <property name="mgr" column="MGR" type="short" length="4"/>
            <property name="hiredate" column="HIREDATE" type="timestamp"/>
            <property name="sal" column="SAL" type="float" length="7"/>
            <property name="comm" column="COMM" type="float" length="7"/>
            <property name="deptno" column="DEPTNO" type="short" length="2"/>
        </class>
    </hibernate-mapping>
##### EmployeeDao.java Dao用のインターフェースを宣言します。S2Hibernateを意識する必要はありません。
    package examples.hibernate.dao;

    import examples.hibernate.entity.Employee;

    public interface EmployeeDao {

        public Employee getEmployee(int empno);
    }
#### EmployeeDaoImpl.java Dao用の実装を記述します。 S2SessionFactory型のフィールドを定義 コンストラクタで、S2SessionFactoryを取得するように記述 各メソッドでS2SessionFactoryからS2Sessionを取得し、処理を記述する
    package examples.hibernate.dao;

    import java.util.List;
    import net.sf.hibernate.Hibernate;
    import org.seasar.hibernate.S2SessionFactory;
    import examples.hibernate.entity.Employee;

    public class EmployeeDaoImpl implements EmployeeDao {

        private static final String HQL = "from Employee where empno = ?";
        private S2SessionFactory sessionFactory_;

        public EmployeeDaoImpl(S2SessionFactory sessionFactory) {
            sessionFactory_ = sessionFactory;
        }

        public Employee getEmployee(int empno) {
            List result = sessionFactory_.getSession().find(
                HQL, new Integer(empno), Hibernate.INTEGER);
            if (result.size() > 0) {
                return (Employee) result.get(0);
            } else {
                return null;
            }
        }
    }
##### Employee.dicon 作成したDaoクラスとorg.seasar.hibernate.impl.S2SessionFactoryImplを追加します。
    <components>
        <include path="j2ee.dicon"/>
        <component class="org.seasar.hibernate.impl.S2SessionFactoryImpl"/>
        <component class="examples.hibernate.dao.EmployeeDaoImpl">
            <aspect>j2ee.requiredTx</aspect>
        </component>
    </components>
##### EmployeeClient.java Daoを実行する基本的な方法は以下のようになります。 作成したdiconファイルのパスを引数にS2Containerを生成 生成したS2ContainerからgetComponentを呼び出し、登録したDaoを取得する 取得したDaoのメソッドを実行する S2Hibernateではトランザクション制御は行なっていません、トランザクションについてはトランザクションの自動制御を参照して下さい。 実行クラスサンプル
    package examples.hibernate.client;

    import org.seasar.framework.container.S2Container;
    import org.seasar.framework.container.factory.S2ContainerFactory;

    import examples.hibernate.service.EmployeeService;

    public class EmployeeClient {

        private static final String PATH =
            "examples/hibernate/client/Employee.dicon";

        public static void main(String[] args) {
            S2Container container = S2ContainerFactory.create(PATH);/* 手順1 */
            container.init();
            try {
                EmployeeService service =
                    (EmployeeService) container.getComponent(EmployeeService.class);/* 手順2 */
                System.out.println(service.getEmployee(7788).getEname());/* 手順3 */
            } finally {
                container.destroy();
            }

        }
    }
##### 実行結果
    DEBUG 2004-04-07 18:53:52,511 [main] トランザクションを開始しました
    2004/04/07 18:53:52 net.sf.hibernate.cfg.Environment <clinit>
    情報: Hibernate 2.1.2
    省略
    DEBUG 2004-04-07 18:53:54,654 [main] 物理的なコネクションを取得しました
    DEBUG 2004-04-07 18:53:54,744 [main] 論理的なコネクションを取得しました
    Hibernate: select employee0_.EMPNO as EMPNO, employee0_.ENAME as ENAME, employee0_.JOB as JOB,
      employee0_.MGR as MGR, employee0_.HIREDATE as HIREDATE, employee0_.SAL as SAL,
      employee0_.COMM as COMM, employee0_.DEPTNO as DEPTNO from EMP employee0_ where (empno=? )
    DEBUG 2004-04-07 18:53:55,605 [main] 論理的なコネクションを閉じました
    DEBUG 2004-04-07 18:53:55,625 [main] トランザクションをコミットしました
    SCOTT
    DEBUG 2004-04-07 18:53:55,625 [main] 物理的なコネクションを閉じました
#### S2hibernate.daoの使い方の例 EmployeeAutoDao EmployeeAutoClient.java dao.dicon 実行結果 ##### EmployeeAutoDao
    package examples.hibernate.dao;

    import java.util.List;
    import examples.hibernate.entity.Employee;

    public interface EmployeeAutoDao {

    	public Class BEAN = Employee.class;

    	//追加、削除、更新、保存or更新をする場合
    	public void save(Employee employee);
    	public void delete(Employee employee);
    	public void update(Employee employee);
    	public void saveOrUpdate(Employee employee);

    	//HQLを指定しないで実行する場合
    	public String getEmployeeByEmpNo_ARGS = "empno";
    	public Employee getEmployeeByEmpNo(long empNo);

    	public String getEmployeeByJobDeptno_ARGS = "job, deptno";
    	public List getEmployeeByJobDeptno(String job, short deptno);

    	//HQLを指定して実行する場合
    	public String getHQLAllEmployee_HQL = "from Employee emp order by emp.empno";
    	public List getHQLAllEmployee();

    	//何も指定していない場合
    	public List getAllEmployee();

    	//firstResult,maxResultsを指定する場合
    	public String getEmployeeList_ARGS = "firstResult,maxResults";
    	public String getEmployeeList_HQL = "from Employee emp order by emp.empno";
    	public List getEmployeeList(int firstResult ,int MaxResults );

    	//戻り値がintの場合
    	public String getEmployeeCount_HQL = "select count(emp) from Employee emp";
    	public int getEmployeeCount();

    	//戻り値がStringの場合
    	public String getEmployeeNameById_HQL
    				= "select emp.ename from Employee emp where empno = :employeeId ";
    	public String getEmployeeNameById_ARGS = "employeeId";
    	public String getEmployeeNameById(Long employeeId);

    	//NamedQuery呼び出しを使う場合
    	//(Employee.hbm.xmlの"examples.hibernate.dao.EmployeeAutoDao_getEmployeeByJob"に対応)
    	public String getEmployeeByJob_ARGS = "job";
    	public List getEmployeeByJob(String job);

    	//NamedQueryで戻り値がStringになるようなSQL文を使う場合
    	//(Employee.hbm.xmlの"examples.hibernate.dao.EmployeeAutoDao_getSQLEmployeeNameById"に対応)
    	public String getSQLEmployeeNameById_ARGS = "employeeId";
    	public String getSQLEmployeeNameById(Long employeeId);

    	//NamedQueryで戻り値がLongになるようなSQL文を使う場合
    	//(Employee.hbm.xmlの"getSQLEmployeeIdByName"NamedQueryを実行)
    	public String getSQLEmployeeIdByName_ARGS = "employeeName";
    	public Long getSQLEmployeeIdByName(String employeeName);
    }
##### EmployeeAutoDao.dicon S2Hibernate.daoを使うのに必要な設定をまとめた"s2hibernate.dicon"をインクルードします。
    <components>
        <include path="s2hibernate.dicon"/>
        <component class="examples.hibernate.dao.EmployeeAutoDao">
            <aspect>j2ee.requiredTx</aspect>
            <aspect>s2hibernate.interceptor</aspect>
        </component>
    </components>
##### s2hibernate.dicon S2Hibernate.daoを使うのに必要な設定をまとめたdiconファイル
    <components namespace="s2hibernate">
        <include path="j2ee.dicon"/>
        <component class="org.seasar.hibernate.impl.S2SessionFactoryImpl"/>
        <component name="interceptor"
    		class="org.seasar.hibernate.dao.interceptors.S2HibernateDaoInterceptor"/>
    </components>
##### EmployeeAutoDaoClient.java diconファイル名以外は、S2Hibernateの基本的な使い方と同じ流れになります。 作成したdiconファイルのパスを引数にS2Containerを生成 生成したS2ContainerからgetComponentを呼び出し、登録したDaoを取得する 取得したDaoのメソッドを実行する
    package examples.hibernate.client;

    import org.seasar.framework.container.S2Container;
    import org.seasar.framework.container.factory.S2ContainerFactory;

    import examples.hibernate.dao.EmployeeAutoDao;
    import examples.hibernate.entity.Employee;

    public class EmployeeAutoDaoClient {

    	private static final String PATH =
    				"examples/hibernate/client/EmployeeAutoDao.dicon";

    	public static void main(String[] args) {
    		S2Container container = S2ContainerFactory.create(PATH);/* 手順1 */
    		container.init();
    		try {
    			EmployeeAutoDao dao = (EmployeeAutoDao) container
    					.getComponent(EmployeeAutoDao.class);/* 手順2 */
    			Employee emp = new Employee();
    			emp.setEmpno( 7788);
    			emp.setEname("SCOTT");
    			emp.setDeptno((short)10);

    			dao.save( emp );	/* 手順3 */

    		} finally {
    			container.destroy();
    		}

    	}
    }
##### 実行結果
    DEBUG 2004-11-11 19:01:50,163 [main] トランザクションを開始しました
    INFO  2004-11-11 19:01:50,323 [main] Hibernate 2.1.6
    省略
    DEBUG 2004-11-11 19:01:51,545 [main] 物理的なコネクションを取得しました
    DEBUG 2004-11-11 19:01:51,645 [main] 論理的なコネクションを取得しました
    省略
    Hibernate: insert into EMP (ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO, EMPNO)
    		values (?, ?, ?, ?, ?, ?, ?, ?)
    省略
    DEBUG 2004-11-11 19:01:52,025 [main] 論理的なコネクションを閉じました
    DEBUG 2004-11-11 19:01:52,025 [main] トランザクションをコミットしました
    DEBUG 2004-11-11 19:01:52,045 [main] 物理的なコネクションを閉じました
| © Copyright The Seasar Project and the others 2004, all rights reserved.