S2Hibernateを使うと、S2のJTAやConnectionPoolとHibernateが簡単に連動するようになります。これまでHibernateで開発するときの悩みの種だったSession管理をS2Hibernateが自動的に行ってくれるので、開発者はSessionのオープン・クローズ、Transaction処理から開放されます。SessionはJTAのトランザクション中は維持され、トランザクションの終了時に自動的にクローズ(flushも)されます。
S2と同様にJDK1.4以上が必要です。S2HibernateVx.x.x.jarを解凍してできたs2hibernateディレクトリをEclipseのJavaプロジェクトとして丸ごとインポートしてください。.classpathを上書きするか聞かれるので、すべてはいのボタンをクリックして、すべてを取り込みます。 これで、私と全く同じ環境になります。src/examples配下にサンプルもあります。
S2Hibernateとして必要なjarファイルは、s2hibernate/libにそろってます。Hibernateはコネクションプールやキャッシュの実装をいろいろ選べるようになっているので、S2Hibernateで用意していない実装が必要な場合は、Hibernateのサイトよりダウンロードしてください。簡単に機能を試すことができるように、RDBMSとしてHSQLDBを用意しています。機能を試す前にあらかじめHSQLDBを実行しておいてください。HSQLDBを実行するには、bin/runHsqldb.batをダブルクリック(Windowsの場合)します。lib/hsqldb.jarはHSQLDBを実行する上では必要ですが、本番では必要ありません。libのjarファイル(hsqldb.jar以外)とsrcのhibernate.cfg.xml、ehcache.xml、j2ee.dicon、log4j.propertiesをCLASSPATHにとおせば、S2Hibernateを実行できます。Eclipseにインポートして使う場合は設定は不要です。
Hibernateを使いたいクラスは、S2SessionFactory型のフィールドを定義してコンストラクタあるいはプロパティ経由で実装クラス(S2SessionFactoryImpl)を受け取ります。あとは、S2SessionFactory.getSession()を呼び出してHibernateの機能を自由に使うことができます。Sessionのオープン・クローズ、トランザクション制御は一切必要ありません。S2SessionFactory.getSession()が返すオブジェクトは、HibernateのSessionのラッパーであるS2Sessionです。実行できるメソッドはHibernateのSessionと同じで、検査例外(HibernateException)を実行時例外(HibernateRuntimeException)に変換してくれます。そのため、HibernateExceptionをcatchしたくないクラスは特に何もする必要はありません。catchする必要がある場合は、HibernateRuntimeExceptionでcatchしてgetCause()でHibernateExceptionを取り出します。
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(long empno, java.lang.String ename, java.lang.String job, Short mgr, java.util.Date hiredate, Float sal, Float comm, short deptno) {
this.empno = empno;
this.ename = ename;
this.job = job;
this.mgr = mgr;
this.hiredate = hiredate;
this.sal = sal;
this.comm = comm;
this.deptno = 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();
}
}
<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>
package examples.hibernate.dao;
import examples.hibernate.entity.Employee;
public interface EmployeeDao {
public Employee getEmployee(int empno);
}
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;
}
}
}
package examples.hibernate.service;
import examples.hibernate.entity.Employee;
public interface EmployeeService {
public Employee getEmployee(int empno);
}
package examples.hibernate.service;
import examples.hibernate.dao.EmployeeDao;
import examples.hibernate.entity.Employee;
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeDao employeeDao_;
public EmployeeServiceImpl(EmployeeDao employeeDao) {
employeeDao_ = employeeDao;
}
public Employee getEmployee(int empno) {
return employeeDao_.getEmployee(empno);
}
}
<components>
<include path="j2ee.dicon"/>
<component class="org.seasar.hibernate.impl.S2SessionFactoryImpl"/>
<component class="examples.hibernate.dao.EmployeeDaoImpl"/>
<component class="examples.hibernate.service.EmployeeServiceImpl">
<aspect>j2ee.requiredTx</aspect>
</component>
</components>
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);
container.init();
try {
EmployeeService service =
(EmployeeService) container.getComponent(EmployeeService.class);
System.out.println(service.getEmployee(7788).getEname());
} finally {
container.destroy();
}
}
}
DEBUG 2004-04-07 18:53:52,511 [main] トランザクションを開始しましたS2Hibernateを使えば、Hibernateのおいしいところだけを簡単に利用できるということが分かっていただけたと思います。
2004/04/07 18:53:52 net.sf.hibernate.cfg.Environment <clinit>
情報: Hibernate 2.1.2
2004/04/07 18:53:52 net.sf.hibernate.cfg.Environment <clinit>
情報: hibernate.properties not found
2004/04/07 18:53:52 net.sf.hibernate.cfg.Environment <clinit>
情報: using CGLIB reflection optimizer
2004/04/07 18:53:52 net.sf.hibernate.cfg.Configuration configure
情報: configuring from url: file:/D:/higa/devroot/s2hibernate/build/hibernate.cfg.xml
2004/04/07 18:53:53 net.sf.hibernate.cfg.Configuration addResource
情報: Mapping resource: examples/hibernate/entity/Employee.hbm.xml
2004/04/07 18:53:53 net.sf.hibernate.cfg.Binder bindRootClass
情報: Mapping class: examples.hibernate.entity.Employee -> EMP
2004/04/07 18:53:53 net.sf.hibernate.cfg.Configuration doConfigure
情報: Configured SessionFactory: null
2004/04/07 18:53:53 net.sf.hibernate.cfg.Configuration secondPassCompile
情報: processing one-to-many association mappings
2004/04/07 18:53:53 net.sf.hibernate.cfg.Configuration secondPassCompile
情報: processing one-to-one association property references
2004/04/07 18:53:53 net.sf.hibernate.cfg.Configuration secondPassCompile
情報: processing foreign key constraints
2004/04/07 18:53:53 net.sf.hibernate.dialect.Dialect <init>
情報: Using dialect: net.sf.hibernate.dialect.HSQLDialect
2004/04/07 18:53:53 net.sf.hibernate.cfg.SettingsFactory buildSettings
情報: Use outer join fetching: false
2004/04/07 18:53:53 net.sf.hibernate.connection.UserSuppliedConnectionProvider configure
警告: No connection properties specified - the user must supply JDBC connections
2004/04/07 18:53:53 net.sf.hibernate.transaction.TransactionManagerLookupFactory getTransactionManagerLookup
情報: No TransactionManagerLookup configured (in JTA environment, use of process level read-write cache is not recommended)
2004/04/07 18:53:53 net.sf.hibernate.cfg.SettingsFactory buildSettings
情報: Use scrollable result sets: false
2004/04/07 18:53:53 net.sf.hibernate.cfg.SettingsFactory buildSettings
情報: Use JDBC3 getGeneratedKeys(): false
2004/04/07 18:53:53 net.sf.hibernate.cfg.SettingsFactory buildSettings
情報: Optimize cache for minimal puts: false
2004/04/07 18:53:53 net.sf.hibernate.cfg.SettingsFactory buildSettings
情報: echoing all SQL to stdout
2004/04/07 18:53:53 net.sf.hibernate.cfg.SettingsFactory buildSettings
情報: Query language substitutions: {}
2004/04/07 18:53:53 net.sf.hibernate.cfg.SettingsFactory buildSettings
情報: cache provider: net.sf.ehcache.hibernate.Provider
2004/04/07 18:53:53 net.sf.hibernate.cfg.Configuration configureCaches
情報: instantiating and configuring caches
2004/04/07 18:53:53 net.sf.hibernate.impl.SessionFactoryImpl <init>
情報: building session factory
2004/04/07 18:53:54 net.sf.hibernate.impl.SessionFactoryObjectFactory addInstance
情報: no JNDI name configured
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] 物理的なコネクションを閉じました