Spring框架學習(4)spring整合hibernate
內容源自: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