2015年7月9日 星期四

整合Spring、Hibernate和C3P0的配置

當我們只有使用Hibernate的時候,其中要獲取SessionFactory的話必須要使用Hibernate的API手動獲取,例如像這樣:

SessionFactory sessionFactory = AnnotationConfiguration().configure().buildSessionFactory();

如果配合Spring的話,就可以使用注入的概念將SessionFactory注入到要使用SessionFactory的類別中。

整合Spring與Hibernate有兩種方法:

  1. 在Spring配置中直接將原Hibernate的配置檔抓進來。
  2. 在Spring自己配置Hibernate的配置、連接池(例如C3P0)等,可以捨棄原來的Hibernate配置檔,也可把它抓進來,然後覆蓋部份配置。

讓我們再一次看一次原來的Hibernate配置檔,hibernate.cfg.xml:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/smarthomeprojectdatabase?zeroDateTimeBehavior=convertToNull</property>
        <property name="hibernate.connection.username">user</property>
        <property name="hibernate.connection.password">pass</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.current_session_context_class">thread</property>
        <!-- 使用ASTQueryTranslatorFactory才可以Inser, Delete, Update -->
        <property name="hibernate.query.factory_class">org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory</property>
        
        <!--==============C3P0的配置=============-->
        <!-- 最小連接數 -->
        <property name="hibernate.c3p0.min_size">5</property>
        <!-- 最大連接數 -->
        <property name="hibernate.c3p0.max_size">20</property>
        <!-- 多久會把無用的連接視為timeout並移除到min_size的連接數量,單位毫秒 -->
        <property name="hibernate.c3p0.timeout">300</property>
        <!-- 最大的PreparedStatement的數量 -->
        <property name="hibernate.c3p0.max_statements">50</property>
        <!-- 多久進行空閒連接的檢查,確定連接還存在,例如有無被Database端關掉,單位是秒-->
        <property name="hibernate.c3p0.idle_test_period">3000</property>
        <!--======================================-->
        
        <mapping resource="DatabaseFunction/SmartDevices.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

可以看到除了Hibernate自己配置外,也加上了C3P0連接池的配置。接著我們在看一下要使用SessionFactory的類別,HibernateUtil.java:

package DatabaseFunction;

import org.hibernate.SessionFactory;

public class HibernateUtil {

    private static SessionFactory sessionFactory = null;

    public HibernateUtil(SessionFactory sessionFactory) {
        try {        
            this.sessionFactory = sessionFactory;
        } catch (Throwable ex) {
            // Log the exception. 
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

可以看到,該類別的建構子會被注入一個SessionFactory的實體物件,如果我們想要用Spring來對該類別進行注入,就必須在Spring的配置文件裡進行Bean的設定(當然你也可以選擇使用Annotation的方式),下面程式碼中的DatabaseFunction只是套件名稱,而因為我們設定對HibernateUtil.java的建構子注入名為sessionFactory的參考,所以之後我們要在Spring中設定id為sessionFactory的Bean:

<bean class="DatabaseFunction.HibernateUtil">
        <constructor-arg ref="sessionFactory" />
</bean>

現在開始演示兩種整合Spring與Hibernate的方法:
  1. 在Spring配置中直接將原Hibernate的配置檔抓進來:

  2. 在Spring的配置檔,例如applicationContext.xml中,我們可以加入以下的Bean:
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <property name="configLocation"
              value="classpath:hibernate.cfg.xml">
            </property>
    </bean>
    

    其中"configLocation"表示把Hibernate的hibernate.cfg.xml設定檔設定到id為sessionFactory的Bean之名為configLocation的屬性中,而該Bean為LocalSessionFactoryBean的實體。

  3. 在Spring自己配置Hibernate的配置、連接池(例如C3P0)等,可以捨棄原來的Hibernate配置檔,也可把它抓進來,然後覆蓋部份配置

  4. 我們也可以在Spring的配置檔中,例如applicationContext.xml中直接設定連接池及Hibernate配置,首先我們先來加入C3P0的池接池設定,其中各項屬性的設定都可對應到之前的C3P0設定:

    <!-- C3P0連接池的配置 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
         <property name="driverClass" value="com.mysql.jdbc.Driver" />
         <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/smarthomeprojectdatabase?zeroDateTimeBehavior=convertToNull" />
         <property name="user" value="user" />
         <property name="password" value="pass" />
         <property name="maxPoolSize" value="20" />
         <property name="minPoolSize" value="5" />
         <property name="maxStatements" value="50" />
         <property name="idleConnectionTestPeriod" value="300" />
    </bean> 

    再來我們加上Hibernate的設定,其中dataSource屬性參考到C3P0配置Bean的id:

    <!-- Hibernate的配置 -->
        <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" destroy-method="destroy"> 
            <!-- 指定數據源,此處是C3P0連接池 -->
            <property name="dataSource" ref="dataSource" />
            <!-- 指定ORM物件關聯表映射檔的設定檔位置 -->
            <property name="mappingResources"> 
                <list> 
                    <value>DatabaseFunction/SmartDevices.hbm.xml</value> 
                </list> 
            </property> 
            <!-- 捨棄原hibernate.cfg.xml檔或
            覆蓋原hibernate.cfg.xml檔的部份設定 -->
            <property name="hibernateProperties"> 
                <props> 
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.current_session_context_class">thread</prop>
                    <prop key="hibernate.query.factory_class">org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory</prop>
                </props> 
            </property> 
        </bean> 

    這樣就配置完成了,其中的各項Hibernate配置也都可以跟原來的hibernate.cfg.xml對應上,此時已經完全可以不用hibernate.cfg.xml也可也使用Spring幫我們注入的SessionFactory了當然也可以保留hibernate.cfg.xml,並向第一種方法那樣,利用"configLocation"屬性來指定hibernate.cfg.xml,此時Spring中有設定的Hibernate屬性將會覆蓋原hibernate.cfg.xml的重覆屬性。

參考資料:

  1. Java Tutorial 第五堂(1)使用 spring-orm 整合 Hibernate
  2. SessionFactory 註入
  3. Spring框架結合Hibernate框架的兩種方式
  4. Spring與Hibernate兩種組合方式
  5. Configuring the built-in c3p0 pooling in Hibernate using Spring
  6. Spring 結合 Hibernate 配置 C3P0

沒有留言 :

張貼留言