發表於 程式分享

hibernate效能

文章:Tomcat啟動很久才完成經過2週終於找到原因並成功解決了~

原因是hibernate的hbm.xml設定檔在Tomcat啟動時需先load至Tomcat memory,但是透過hbm.xml檔load至memory需要I/O及memory,故會花費許久,因table共70多個,而且有些table的欄位很多,故造成Tomcat需啟動許久。
我試了以下3種hbm.xml的設定均無法降低啟動時間:

<property name="mappingDirectoryLocations">
    <list>
        <value>classpath:com/xxx/bean/</value>
    </list>
</property>

<property name="mappingLocations">
    <list>
        <value>classpath:com/xxx/bean/*.hbm.xml</value>
        ...
    </list>
</property>

<property name="mappingResources">
    <list>
        <value>com/xxx/bean/PRCmdCfg.hbm.xml</value>
        ...
    </list>
</property> 

後來,試著將設定檔內sql調整成直接寫在程式內而不用hbm.xml設定的方式,啟動效能並未改善:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC    
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  "http://hibernate.org/dtd/hibernate-mapping"> 
<hibernate-mapping> 
  <class name="com.xxx.bean.PRUnit" table="PRUnit"> 
   ...
  </class>
    <sql-query name="findPRUnitWithDetail">
        <return alias="t1" class="com.xxx.bean.PRUnit"/>
        <return alias="t2" class="com.xxx.bean.PRFuncCfg"/>
        <return alias="t3" class="com.xxx.bean.PRCmdCfg"/>
        <return alias="t4" class="com.xxx.bean.PRCode"/>
        <return alias="t5" class="com.xxx.bean.PRCode"/>
        <return alias="t7" class="com.xxx.bean.PRMenuCfg"/>
        <![CDATA[
        SELECT {t1.*}, {t2.*}, {t3.*}, {t4.*}, {t5.*}, {t7.*} 
          FROM PRUnit t1
          JOIN PRFuncCfg t2
            ON t1.platForm = t2.platForm
           AND t1.funcId   = t2.funcId
          JOIN PRCmdCfg t3
            ON t1.platForm = t3.platForm
           AND t1.funcId   = t3.funcId  
           AND t1.cmdId    = t3.cmdId      
          JOIN PRCode t4
            ON t4.CodeType = 'UNIT'
           AND t1.unitId   = t4.CodeId
          JOIN PRCode t5
            ON t5.CodeType = 'PLFM'
           AND t1.platForm = t5.CodeId  
          JOIN PRMenuCfg t7
            ON t2.platForm = t7.platForm
           AND t2.menuId   = t7.menuId                 
         WHERE t1.unitId 
               in (SELECT t8.unitId 
                     FROM PREmpUnit t8 
                    WHERE t8.empId=:EmpId AND t8.cmdEnable = 1)
           AND t1.cmdEnable = 1 
        ]]>
    </sql-query>
</hibernate-mapping>

最後,只好用最麻煩的方式,取消hbm.xml的設定,改為直接在class設定

...

@Entity
@Table(name = "PRUnit")
public class PRUnit implements Serializable {
    @EmbeddedId
    @AttributeOverrides({
        @AttributeOverride(
            name = "platForm",
            column = @Column(name = "platForm")),
        @AttributeOverride(
            name = "unitId",
            column = @Column(name = "unitId")),
        @AttributeOverride(
            name = "funcId",
            column = @Column(name = "funcId")),
        @AttributeOverride(
            name = "cmdId",
            column = @Column(name = "cmdId"))
    })
    private PRUnitPK PRUnitPK;
    @Column(name = "cmdEnable")
    private int cmdEnable;
    @Column(name = "cfgVal")
    private String cfgVal;
    @Column(name = "optVal")
    private String optVal;
    @Column(name = "modifyTime")
    private Date modifyTime;
    @Column(name = "modifyEmp")
    private String modifyEmp;

    public PRUnit() {
        
    }
    
    public PRUnit(PRUnitPK PK) {
        this.PRUnitPK = PK;
    }

    public PRUnitPK getPRUnitPK() {
        return PRUnitPK;
    }

    public void setPRUnitPK(PRUnitPK pRUnitPK) {
        PRUnitPK = pRUnitPK;
    }

    public int getCmdEnable() {
        return cmdEnable;
    }

    public void setCmdEnable(int cmdEnable) {
        this.cmdEnable = cmdEnable;
    }

    public String getCfgVal() {
        return cfgVal;
    }

    public void setCfgVal(String cfgVal) {
        this.cfgVal = cfgVal;
    }

    public String getOptVal() {
        return optVal;
    }

    public void setOptVal(String optVal) {
        this.optVal = optVal;
    }

    public Date getModifyTime() {
        return modifyTime;
    }

    public void setModifyTime(Date modifyTime) {
        this.modifyTime = modifyTime;
    }

    public String getModifyEmp() {
        return modifyEmp;
    }

    public void setModifyEmp(String modifyEmp) {
        this.modifyEmp = modifyEmp;
    }

    @Override
    public String toString() {
        return "PRUnit [PRUnitPK=" + PRUnitPK + ", cmdEnable=" + cmdEnable + ", cfgVal=" + cfgVal + ", optVal=" + optVal
                + ", modifyTime=" + modifyTime + ", modifyEmp=" + modifyEmp + "]";
    }   
}

而applicationContext.xml調整為下面任一方式,Tomcat均能在1、2分鐘內啟動完畢

<property name="packagesToScan">
    <list>
        <value>com.xxx.bean</value>
    </list>
</property>
<property name="mappingDirectoryLocations">
    <list>
        <value>classpath:com/xxx/bean/</value>
    </list>
</property>

究其原因,猜測是hibernate在load hbm.xml需要花費較多的I/O及memory,故造成啟動花費超久,
剛開始使用此架構因table尚少沒感覺,等系統愈來愈大就開始造成困擾了~還好調整後能修正此問題,
要不然整個架構大改,就不是花幾天能完成的~

發表留言