1. 程式人生 > >Spring框架學習(4)spring整合hibernate

Spring框架學習(4)spring整合hibernate

location host mage too 自動 exception 4.0 數據庫連接 find

內容源自:spring整合hibernate spring整合註解形式的hibernate

這裏和上一部分學習一樣用了模板模式, 將hibernate開發流程封裝在ORM層提供的模板類HibernateTemplate中,通過在DAO中對模板類的使用,實現對傳統hibernate開發流程的代替。

一、先來看看Hibernate的傳統開發流程:

1) 配置SessionFactory對象

hibernate.cfg.xml <session-factory>

a 數據源 driver_class url username password

b 映射文件 mapping

c 可選參數 show_sql format_sql dialect ...

2) 創建SessionFactory實例

工廠類 - 解析xml - SessionFactory

3) 獲取會話 Session sessionFactory.getSession()

  • 如果是 insert delete update

4) 開啟事務 Transaction

session.beginTransaction()

5) 執行操作save() delete() update()

6) 提交/回滾事務 commit() / rollback()

  • 如果是 select

4) 定義執行hql語句

5) 編譯hql Query session.createQuery()

6) 執行hql list() unqueObject()

7) 關閉會話 session.close()

spring中hibernate的使用和傳統hibernate使用基本類似,同樣要在配置文件中配置SessionFactory、數據源等,只不過,spring 要在容器中配置HibernateTemplate,通過將這個bean對象註入到dao層,來完成數據庫的操作。

二、整合過程:

1) 添加spring框架支持(core層)

2) 添加spring整合hibernate需要的jar(hibernate目錄)

3) 添加hibernate支持(導入3.5/3.6版本jar包)spring4.0中,如果以註解的方式整合hibernate,僅支持hibernate3.6及以上版本

4) 反向生成表對應的javaBean和映射文件

5)編寫applicationContext.xml文件添加支持

三、具體實現:

測試項目目錄如下:

技術分享圖片

applicationContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
         <!-- 
            StuDaoImpl hibernateTemplate配置成ioc容器
          -->
    <bean id="dao" class="com.etoak.dao.CityDaoImpl">
        <property name="ht" ref="ht"></property>
    </bean>

    <!-- 
        此時的HibernateTemplate暫時不具備數據庫的連接能力
        需要為其提供一個SessionFactory對象
            1 數據源~描述當前需要連接的數據庫
            2 映射文件~描述當前需要對哪個表進行操作
            setSessionFactory()
     -->
    <bean id="ht" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sf"></property>
    </bean>
    <!-- 
        配置SessionFactory[接口]對象
            1 實現類
                spring框架內部並沒有提供SessionFactory實現類
            2工廠bean
                spring為SessionFactory提供了一個工廠類進行實例化
                    LocalSessionFactoryBean impliments FactoryBean
        如何使用這個工廠配置SessionFactory對象?
            和hibernate配置的方式類似
            1 數據源
                setDataSource(DataSource ds)
            2映射文件
                setMappingResources(String[] mapping)
            3 可選參數
                setHibernateProperties(Properties props)
            list元素:表示調用當前setter方法需要註入的參數類型
                    每在工程中添加一個映射文件,就需要在list元素下添加
                        一個value子元素指向該映射文件
     -->
    <bean id="sf" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="ds"></property>
        <property name="mappingResources" >
            <list>  
                <value>com/etoak/po/City.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
            </props>
        </property>
    </bean>
    <!-- 
        配置DataSource數據源

     -->
      <bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/yitu"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
      </bean>

</beans>

CityDaoImpl.java(dao)

package com.etoak.dao;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.etoak.po.City;

/**
 * 使用hibernate方式對city進行crud操作
 * spring提供的整合方案  HibernateTemplate
 * @author D_xiao
 *
 */
public class CityDaoImpl {
    private HibernateTemplate ht;

    public void setHt(HibernateTemplate ht) {
        this.ht = ht;
    }

    public boolean addCity(City city){
        Serializable se = ht.save(city);
        //se 添加成功後該數據的主鍵值
        Integer id = (Integer)se;
        return id>0;
    }

    /**
     * 根據主鍵查詢單條數據
     * get  立即加載
     *          一級緩存 - 二級緩存 - 數據庫  - null
     * load 延遲加載[數據庫連接延遲]
     *      查詢階段        
     *          一級緩存 ->終止查詢,返回代理對象
     *      使用階段
     *          二級緩存 ->數據庫 -> Exception
     *      代理模式 
     *      判斷能否使用load方法,
     * 這裏不能用load 只能用get
     */         
    public City selectCityById(Integer id){
        return ht.get(City.class, id);
    }
    //這裏無法控制成功失敗,只有在添加事務後才能控制
    public boolean delCityById(Integer id){
        ht.delete(ht.load(City.class, id));//這裏可以用load,因為在查詢(對象)和使用(刪除)中有會話
        return true;
    }

    public boolean updateCity(City city){
        ht.update(city);
        return true;
    }
    //查詢批量數據 List<City>
    public List selectAllCity(){
        String hql = "from City";
        List list = ht.find(hql);
        return list;
    }

    //非主鍵查詢單條數據  
    public City selectCityByName(String name){
        String hql = "from City where name=?";
        Object[] args = {name};
        List list = ht.find(hql,args);
        if(list.size()!=0)
            return (City)list.get(0);
        else 
            return null;

    }

    //查詢數據量
    //hibernate3.2之後查詢數據量返回類型都為long類型
    public long selectCityCount(){
        String hql = "select count(*) from City";
        List list = ht.find(hql);
        return (long)list.get(0);
    }

    /**
     * 分頁查詢
     * hibernate中分頁查詢:
     *      setFirstResult()  setMaxResult()
     * HibernateTemplate 中提供的方法(save update delete get load find)默認封裝了hibernate整套流程
     * 但該模板類中爺提供了一部分方法僅封裝了hibernate部分功能
     *      execute(HibernateCallback[接口] c1)
     *          T  當前需要查詢的數據類型
     * 匿名內部類訪問外部屬性  需將屬性設置為final
     */
    public List<City> selectCityByPage(final int start,final int end){
        return ht.execute(new HibernateCallback<List<City>>(){
            //該方法僅封裝了會話session的創建
            @Override
            public List<City> doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Query query = session.createQuery("from City");
                query.setFirstResult(start);
                query.setMaxResults(end);
                return query.list();
            }

        });
    }
}

利用hibernate反向自動生成的配置文件也貼一下吧:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="com.etoak.po.City" table="city" catalog="yitu">
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="native" />
        </id>
        <property name="pid" type="java.lang.Integer">
            <column name="pid" />
        </property>
        <property name="name" type="java.lang.String">
            <column name="name" length="10" />
        </property>
    </class>
</hibernate-mapping>

下面我們來總結下如何整合註解形式的hibernate
我們知道在普通hibernate中,表與實體的映射關系是寫在映射關系文件當中的,一個實體類對應一個映射關系配置文件。而在註解形式中是沒有這個映射關系文件的,關系直接在實體類中通過註解的方式展現,所以寫法上略有些不同。
下面我們通過一個例子來看看他們的區別。還是使用上面的例子,先去掉這個hibernate反向生成的City.hbm.xml文件。

技術分享圖片

Dao層裏面是不需要修改的,實現方法都一樣。
改一下City.java 和配置文件applicationContext.xml即可

applicationContext.xml:
兩種方式的區別就是sessionFactory的配置上不同。在配置SessionFactory接口對象時,spring框架內部並沒有提供SessionFactory實現類,所以我們采用工廠bean的方式來配置。spring提供工廠實現類對SessionFactory進行實例化。整合普通方式采用LocalSessionFactoryBean,整合註解方式采用AnnotationSessionFactoryBean
所以上面的配置文件修改如下:

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
         <!-- 
            StuDaoImpl hibernateTemplate配置成ioc容器
          -->
    <bean id="dao" class="com.etoak.dao.CityDaoImpl">
        <property name="ht" ref="ht"></property>
    </bean>


    <bean id="ht" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sf"></property>
    </bean>

    <!-- 
        hibernate註解形式(不存在映射文件):
            使用AnnotationSessionFactoryBean工廠bean進行配置
                1 配置數據源 setDataSource
                2 配置映射實體bean  兩種方法:
                    a setAnnotatedClasses(Claesses[] class) 指向映射實體bean列表
                      每在工程中添加一個實體bean對象,需要在list中添加一個value指向
                    b setPackagesToScan(String package)
                     掃描實體bean所在的包結構,在包下查找所有的映射
                3 配置可選參數
     -->

    <bean name="sf" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="ds"></property>
        <!-- 
        第一種方法映射實體bean
        <property name="annotatedClasses">
            <list>
                <value>com.etoak.po.City</value>
            </list>
        </property> -->
        <!-- 第二種方法映射實體bean -->
        <property name="packagesToScan" value="com.etoak.po"></property><!-- 如果有多個包有映射實體,都在value中寫,用逗號隔開 -->
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

      <bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/yitu"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
      </bean>

</beans>

City.java實體類添加註解:

package com.etoak.po;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="city",catalog="yitu")
public class City implements java.io.Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)  //自增長策略
    private Integer id;
    @Column(name="pid")
    private Integer pid;
    @Column(name="name")
    private String name;

    // Constructors

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

    /** full constructor */
    public City(Integer pid, String name) {
        this.pid = pid;
        this.name = name;
    }
    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getPid() {
        return this.pid;
    }

    public void setPid(Integer pid) {
        this.pid = pid;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Spring框架學習(4)spring整合hibernate