Hibernateの利用

以前に作成した建築アプリケーションをHibarnateを使用したアプリに改造する。

概念図

DB

DBのER図を以下に表す。

Bean設定ファイル

DatabaseBeans.xml

データベースに接続する為のプロパティ、Hibernateの設定を書いたファイル

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- データソースの設定 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    	<property name="driverClassName">
    		<value>com.mysql.jdbc.Driver</value>
    	</property>
    	
    	<property name="url">
    		<value>jdbc:mysql://localhost:3306/constract</value>
    	</property>
    	
    	<property name="username">
    		<value>root</value>
    	</property>
    	<property name="password">
    		<value></value>
    	</property>
    </bean>
    
    <!-- セッションファクトリーの設定 -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="mappingResources">
			<value>
				jp/co/jjjjpppp/springtest/model/Company.hbm.xml, 
				jp/co/jjjjpppp/springtest/model/User.hbm.xml, 
				jp/co/jjjjpppp/springtest/model/Work.hbm.xml,
				jp/co/jjjjpppp/springtest/model/Contract.hbm.xml
			</value>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">
					org.hibernate.dialect.MySQLDialect
				</prop>
				<prop key="hibernate.show_sql">true</prop>
			</props>
		</property>
	</bean>
</beans>
DaoBeans.xml

データベースアクセス層のBeans設定 *全てにsesseionFactoryをインジェクションしなくてはならない

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
   <bean id="contractDao" class="jp.co.jjjjpppp.springtest.dao.impl.ContractDaoImpl">
   		<property name="sessionFactory" ref="sessionFactory"></property>
   </bean>
</beans>

Javaファイル

Main.java

DaoBeans.xml、DatabaseBeans.xmlを読込むように変更

/**
 * SpringFrameworkTest 2008/07/07
 */
package jp.co.jjjjpppp.springtest.service.impl;

import java.util.Locale;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		String[] config = { "ServiceBeans.xml",
				"ServiceBeans2.xml",
				"DatabaseBeans.xml", 
				"DaoBeans.xml"};

		ConfigurableApplicationContext appCon = new FileSystemXmlApplicationContext(
				config);

		Man man = (Man) appCon.getBean("proxy");

		man.buyHouse();

	}

}
Oobayashigume.java

Daoを利用しDBへアクセス

/**
 * SpringFrameworkTest 2008/07/07
 */
package jp.co.jjjjpppp.springtest.service.impl;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import jp.co.jjjjpppp.springtest.HouseMaker;
import jp.co.jjjjpppp.springtest.dao.ContractDao;
import jp.co.jjjjpppp.springtest.model.Contract;

public class Oobayashigumi implements HouseMaker {

	/** 協力建築会社 */
	public List<ConstructionCompany> subcontractList;

	/** 建築の利害関係者 */
	public Map stakesHolderMap;

	/** 建築の工法 */
	public Properties methodProperties;

	public ContractDao contractDao;

	/**
	 * @see jp.co.jjjjpppp.springtest.HouseMaker#createHouse()
	 */
	@Override
	public void createHouse() {

		List contractList = contractDao.loadAll();

		Iterator<Contract> it = contractList.iterator();
		while (it.hasNext()) {
			Contract contract = it.next();
			System.out.println(contract.getWork().getName() + " "
					+ contract.getCompany().getName() + " "
					+ contract.getUser().getName());
		}
	}

	/**
	 * @param stakesHolderMap
	 *            the stakesHolderMap to set
	 */
	public void setStakesHolderMap(Map stakesHolderMap) {
		this.stakesHolderMap = stakesHolderMap;
	}

	/**
	 * @param methodProperties
	 *            the methodProperties to set
	 */
	public void setMethodProperties(Properties methodProperties) {
		this.methodProperties = methodProperties;
	}

	/**
	 * @param subcontractList
	 *            the subcontractList to set
	 */
	public void setSubcontractList(List<ConstructionCompany> subcontractList) {
		this.subcontractList = subcontractList;
	}

	/**
	 * @param contractDao
	 *            the contractDao to set
	 */
	public void setContractDao(ContractDao contractDao) {
		this.contractDao = contractDao;
	}

}
ContractDaoImpl.java

新規作成、getClazzメソッドを実装し、loadAll使用時にクラスを引数に渡さなくても、Daoに応じたClassを渡すように変更

package jp.co.jjjjpppp.springtest.dao.impl;

import java.util.List;

import jp.co.jjjjpppp.springtest.dao.ContractDao;
import jp.co.jjjjpppp.springtest.model.Contract;

import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class ContractDaoImpl extends HibernateDaoSupport implements ContractDao{

	public Class getClazz(){
		return Contract.class;
	}
	
	public List loadAll(){
		HibernateTemplate hibernateTemplate = getHibernateTemplate();
		return hibernateTemplate.loadAll(getClazz());
	}
}

Hibernateモデルファイル群

MiddlegenIDEを使用し自動生成した。その際にDBへアクセスするドライバを指定するのだが「commons-dbcp.jar」(DatabaseBeans.xmlを見てみると、このアーカイブ以下のBasicDataSourceを利用しているので、、、)を指定したところうまく動かず。自前で用意したドライバを指定したところ、問題なく動作。Springのjarの中にドライバが存在すると思うのだが、どれだ??
Middelegen公式 http://sourceforge.net/projects/middlegen

例としてcontractテーブルのマッピングファイル、モデルファイルを載せる

Contract.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
    
<hibernate-mapping>
<!-- 
    Created by the Middlegen Hibernate plugin 2.2

    http://boss.bekk.no/boss/middlegen/
    http://www.hibernate.org/
-->

<class 
    name="jp.co.jjjjpppp.springtest.model.Contract" 
    table="contract"
    lazy="false"
>

    <id
        name="contractId"
        type="java.lang.Integer"
        column="CONTRACT_ID"
    >
    
        <generator class="assigned" />
    </id>

    <property
        name="timestamp"
        type="java.sql.Timestamp"
        column="TIMESTAMP"
        length="19"
    />

    <!-- Associations -->
  
    <!-- bi-directional many-to-one association to Work -->
    <many-to-one
        name="work"
        class="jp.co.jjjjpppp.springtest.model.Work"
        not-null="true"
    >
        <column name="WORK_ID" />
    </many-to-one>
    <!-- bi-directional many-to-one association to Company -->
    <many-to-one
        name="company"
        class="jp.co.jjjjpppp.springtest.model.Company"
        not-null="true"
    >
        <column name="COMPANY_ID" />
    </many-to-one>
    <!-- bi-directional many-to-one association to User -->
    <many-to-one
        name="user"
        class="jp.co.jjjjpppp.springtest.model.User"
        not-null="true"
    >
        <column name="USER_ID" />
    </many-to-one>

</class>
</hibernate-mapping>
Contract.java
package jp.co.jjjjpppp.springtest.model;

import java.io.Serializable;
import java.util.Date;
import org.apache.commons.lang.builder.ToStringBuilder;


/** @author Hibernate CodeGenerator */
public class Contract implements Serializable {

    /** identifier field */
    private Integer contractId;

    /** nullable persistent field */
    private Date timestamp;

    /** persistent field */
    private jp.co.jjjjpppp.springtest.model.Work work;

    /** persistent field */
    private jp.co.jjjjpppp.springtest.model.Company company;

    /** persistent field */
    private jp.co.jjjjpppp.springtest.model.User user;

    /** full constructor */
    public Contract(Integer contractId, Date timestamp, jp.co.jjjjpppp.springtest.model.Work work, jp.co.jjjjpppp.springtest.model.Company company, jp.co.jjjjpppp.springtest.model.User user) {
        this.contractId = contractId;
        this.timestamp = timestamp;
        this.work = work;
        this.company = company;
        this.user = user;
    }

    /** default constructor */
    public Contract() {
    }

    /** minimal constructor */
    public Contract(Integer contractId, jp.co.jjjjpppp.springtest.model.Work work, jp.co.jjjjpppp.springtest.model.Company company, jp.co.jjjjpppp.springtest.model.User user) {
        this.contractId = contractId;
        this.work = work;
        this.company = company;
        this.user = user;
    }

    public Integer getContractId() {
        return this.contractId;
    }

    public void setContractId(Integer contractId) {
        this.contractId = contractId;
    }

    public Date getTimestamp() {
        return this.timestamp;
    }

    public void setTimestamp(Date timestamp) {
        this.timestamp = timestamp;
    }

    public jp.co.jjjjpppp.springtest.model.Work getWork() {
        return this.work;
    }

    public void setWork(jp.co.jjjjpppp.springtest.model.Work work) {
        this.work = work;
    }

    public jp.co.jjjjpppp.springtest.model.Company getCompany() {
        return this.company;
    }

    public void setCompany(jp.co.jjjjpppp.springtest.model.Company company) {
        this.company = company;
    }

    public jp.co.jjjjpppp.springtest.model.User getUser() {
        return this.user;
    }

    public void setUser(jp.co.jjjjpppp.springtest.model.User user) {
        this.user = user;
    }

    public String toString() {
        return new ToStringBuilder(this)
            .append("contractId", getContractId())
            .toString();
    }

}
実行時コンソール表示

log4jがWARN吐き出してる。なんだこりゃ?前まではlogがコンソールに出力されていたのに。とりあえず放置ですな。

log4j:WARN No appenders could be found for logger (org.springframework.context.support.FileSystemXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
[LOG] METHOD: buyHouse is calling.
Hibernate: select this_.CONTRACT_ID as CONTRACT1_3_, this_.TIMESTAMP as TIMESTAMP3_3_, this_.WORK_ID as WORK3_3_3_, this_.COMPANY_ID as COMPANY4_3_3_, this_.USER_ID as USER5_3_3_, work2_.WORK_ID as WORK1_0_, work2_.NAME as NAME2_0_, work2_.DATE as DATE2_0_, company3_.COMPANY_ID as COMPANY1_1_, company3_.NAME as NAME0_1_, user4_.USER_ID as USER1_2_, user4_.NAME as NAME1_2_ from contract this_ left outer join work work2_ on this_.WORK_ID=work2_.WORK_ID left outer join company company3_ on this_.COMPANY_ID=company3_.COMPANY_ID left outer join user user4_ on this_.USER_ID=user4_.USER_ID
ボスポラス海峡海底トンネル 大成建設 トルコ
パーム島の海底トンネル 大成建設 アラブ首長国連邦
両国国技館 鹿島建設 司法省
最高裁判所 鹿島建設 司法省
六本木ヒルズ 大林組 森ビル
大阪ドーム 大林組 大阪シティドーム
[LOG] METHOD: buyHouse was called.
[LOG] 処理時間: 0秒

Hibernateのセッション管理

Hibernateではupdateメソッドを呼び出ししなくても、DBへ反映されてしまう?
Hibernateでは、トランザクションの開始から、終了までの間に「Session管理化のオブジェクト」に対する変更はすべて、DBへ反映されるらしい。
ここで言うSessionとはHibarnate独自のもの、永続オブジェクトはSession管理下。
トランザクションを明示的書いてない場合、暗黙的にHibernateTemplateクラスのメソッド開始時。