您好,登錄后才能下訂單哦!
1、Spring整合ORM方案的好處:
方便基礎(chǔ)設(shè)施的搭建。不同的ORM技術(shù)都有一套自己的方案以初始化框架、搭建基礎(chǔ)設(shè)施等。在搭建基礎(chǔ)設(shè)施中,數(shù)據(jù)源是不可或缺的資源,不同的ORM框架的實現(xiàn)方式各不相同。Spring針對不同的ORM框架,采用相同的方式配置數(shù)據(jù)源,并為不同的ORM框架提供相同的FactoryBean,用以初始化ORM框架的基礎(chǔ)設(shè)施,可以把它們當(dāng)成普通Bean對待。
異常封裝。Spring能夠轉(zhuǎn)化各種ORM框架拋出的異常,將ORM框架專有的或檢查型異常轉(zhuǎn)換為SpringDAO異常體系中的標(biāo)準(zhǔn)異常。這樣用戶就可以有選擇地在適當(dāng)?shù)牡胤教幚砀信d趣的異常,忽略不可恢復(fù)的異常。
統(tǒng)一的事務(wù)管理。通過使用基于SpringDAO模板編程風(fēng)格,甚至使用原生的ORM框架的API,只要遵循Spring所提出的少量編程要求,就可以使用Spring提供的事務(wù)管理功能。Spring為不同的ORM框架提供了對應(yīng)的事務(wù)管理器,可用聲明式事務(wù)管理,并且透明地實現(xiàn)本地事務(wù)管理到全局JTA事務(wù)管理的切換。
允許混合使用多個ORM框架。Spring在DAO層異常、事務(wù)、資源等高級層次建立了抽象,可以讓業(yè)務(wù)層對DAO具體實現(xiàn)的技術(shù)不敏感。這樣開發(fā)者就可以在底層選用合適的實現(xiàn)方式,甚至可以混合使用多種ORM,一般的CRUD使用Hibernate,而數(shù)據(jù)查詢使用iBatis或SpringJDBC。
方便單元測試。Spring容器使得替換不同的實現(xiàn)和配置方式變得很簡單,這有利于單元測試
2、Spring整合Hibernate步驟
2.1 配置SessionFactory(可自動完成)
使用Hibernate框架的第一個工作是編寫Hibernate的配置文件,接著使用這些配置文件實例化SessionFactory,創(chuàng)建好Hibernate的基礎(chǔ)設(shè)施。Spring為創(chuàng)建SessionFactory提供了FactoryBean工廠類:org.springframework.orm.hibernate3.LocalSessionFactoryBean,通過一些必要的配置,即可或缺一個SessionFactoryBean。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <context:component-scan base-package="org.worm.biz.springmvc"/> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username = "${jdbc.username}" p:password = "${jdbc.password}"/> <!-- 也可以使用p:mappingDirectoryLocations來指定多個放置Hibernate映入文件的目錄 --> <bean id="sessionFactory" class = "org.springframework.orm.hibernate3.LocalSessionFactoryBean" p:dataSource-ref = "dataSource" p:mappingLocations="classpath:org/worm/biz/springmvc/dao/*.hbm.xml"> <!-- 指定Hibernate配置文件 --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.formate_sql">true</prop> </props> </property> </bean> <!-- 配置HibernateTemplate Bean --> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" p:sessionFactory-ref="sessionFactory"/> <!-- 配置Hibernate事務(wù)管理 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory"/> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
2.2、使用HibernateTemplate
基于模板類使用Hibernate是最簡單的方式,它可以在不犧牲Hibernate強(qiáng)大功能的情況下,以一種更簡潔的方式使用Hibernate,極大地降低了Hibernate的使用難度。
package org.worm.biz.springmvc.dao.hibernate; import java.util.List; public interface IBaseDao<T> { /** * 保存實體對象 * @param t 實體對象 * */ public void addEntity(T t); /** * 更新實體對象 * @param t 實體對象 * */ public void updateEntity(T t); /** * 獲取實體對象 * @param serialNo 主鍵 * */ public T getEntity(String serialNo,T t); /** * 獲取實體對象集 * @param hql 查詢語句 * @param params 查詢條件 * */ public List<T> getEntities(String hql,Object[] params); /** * 獲取實體對象集 * */ public List<T> getEntitiesByExample(T t); } package org.worm.biz.springmvc.dao.hibernate; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.HibernateTemplate; public class BaseDao<T> implements IBaseDao<T> { private Class entityClass;//Dao的泛型類型,即子類所指定的T所對應(yīng)的類型 public BaseDao() { Type genType = getClass().getGenericSuperclass(); Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); entityClass = (Class) params[0]; } @Autowired private HibernateTemplate hibernateTemplate; public HibernateTemplate getHibernateTemplate() { return hibernateTemplate; } public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; } @Override public void addEntity(T t) { // TODO Auto-generated method stub getHibernateTemplate().save(t); } @Override public void updateEntity(T t) { // TODO Auto-generated method stub getHibernateTemplate().update(t); } @Override public T getEntity(String serialNo) { // TODO Auto-generated method stub return (T) getHibernateTemplate().get(entityClass, Integer.valueOf(serialNo)); } @Override public List<T> getEntities(String hql, Object[] params) { // TODO Auto-generated method stub return (List<T>) getHibernateTemplate().find(hql, params); } @Override public List<T> getEntitiesByExample(T t) { // TODO Auto-generated method stub return getHibernateTemplate().findByExample(t); } } package org.worm.biz.springmvc.dao.hibernate; import org.springframework.stereotype.Repository; import org.worm.biz.springmvc.dao.User; @Repository public class UserDao extends BaseDao<User>{ //添加自身獨(dú)有的業(yè)務(wù) }
2.3、使用Hibernate原生Hibernate API
使用Hibernate原生API與在Spring中使用HibernateTemplate中使用和事務(wù)綁定的Session相同
package org.worm.biz.springmvc.dao.hibernate; import java.util.List; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.worm.biz.springmvc.dao.User; public class BaseDao implements IBaseDao<User> { // @Autowired // private HibernateTemplate hibernateTemplate; // // public HibernateTemplate getHibernateTemplate() { // return hibernateTemplate; // } // // public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { // this.hibernateTemplate = hibernateTemplate; // } @Autowired private SessionFactory sessionFactory; @Override public void addEntity(User t) { // TODO Auto-generated method stub // getHibernateTemplate().save(t); sessionFactory.getCurrentSession().save(t); } @Override public void updateEntity(User t) { // TODO Auto-generated method stub // getHibernateTemplate().update(t); sessionFactory.getCurrentSession().update(t); } @Override public User getEntity(String serialNo, User t) { // TODO Auto-generated method stub // return (User) getHibernateTemplate().get(t.getClass(), Integer.valueOf(serialNo)); return (User) sessionFactory.getCurrentSession().get(t.getClass(), Integer.valueOf(serialNo)); } @Override public List<User> getEntities(String hql, Object[] params) { // TODO Auto-generated method stub // return (List<User>) getHibernateTemplate().find(hql, params); return null; } @Override public List<User> getEntitiesByExample(User t) { // TODO Auto-generated method stub // return getHibernateTemplate().findByExample(t); return null; } }
2.4、使用注解配置Entity
package org.worm.biz.springmvc.dao; import javax.persistence.*; @Entity //@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @Table(name = "t_user") public class User{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "user_no") protected int userId; @Column(name = "user_nick_name") protected String userName; protected String password; @Column(name = "user_age") protected String userAge; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUserAge() { return userAge; } public void setUserAge(String userAge) { this.userAge = userAge; } }
Hibernate通過AnnotationConfiguration的addAnnotatedClass()方法加載使用JPA注解的實體類,獲取映射的元數(shù)據(jù)信息, 并在此基礎(chǔ)上創(chuàng)建SessionFactory實例。AnnotationSessionFactoryBean擴(kuò)展了LocalSessionFactoryBean類,增強(qiáng)的功能是:可以根據(jù)實體類的注解獲取ORM的配置信息。也允許混合使用XML配置和注解配置對象關(guān)系映射,Hibernate內(nèi)部自動整合這些元數(shù)據(jù)信息,不會產(chǎn)生沖突。Spring為了可以通過掃描方式加載帶注解的實體類,提供了一個好用的packagesToScan屬性,可以指定一系列的包名,Spring將掃描并加載這些包(包含子包)路徑的所有帶注解實體類。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <context:component-scan base-package="org.worm.biz.springmvc"/> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username = "${jdbc.username}" p:password = "${jdbc.password}"/> <!-- 也可以使用p:mappingDirectoryLocations來指定多個放置Hibernate映入文件的目錄 --> <!-- <bean id="sessionFactory" class = "org.springframework.orm.hibernate3.LocalSessionFactoryBean" --> <!-- p:dataSource-ref = "dataSource" --> <!-- p:mappingLocations="classpath:org/worm/biz/springmvc/dao/*.hbm.xml"> --> <!-- <property name="hibernateProperties"> --> <!-- <props> --> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> --> <!-- <prop key="hibernate.show_sql">true</prop> --> <!-- <prop key="hibernate.formate_sql">true</prop> --> <!-- </props> --> <!-- </property> --> <!-- </bean> --> <!-- 帶注解實體類 --> <bean id="sessionFactory_1" class = "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" p:dataSource-ref = "dataSource"> <!-- 通過掃描方式加載帶注解的實體類 --> <property name="packagesToScan" value="org.worm.biz.springmvc.dao"/> <!-- 指定Hibernate配置文件 --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.formate_sql">true</prop> </props> </property> </bean> <!-- 配置HibernateTemplate Bean --> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" p:sessionFactory-ref="sessionFactory"/> <!-- 配置Hibernate事務(wù)管理 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory"/> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
2.5 統(tǒng)一使用事務(wù)管理,詳情配置請見2.2
3、延遲加載問題
Hibernate允許對關(guān)聯(lián)對象、屬性進(jìn)行延遲加載,但是必須保證延遲加載的操作限于同一個Hibernate Session范圍之內(nèi)進(jìn)行。如果Service層返回一個啟用了延遲加載功能領(lǐng)域?qū)ο蠼oWeb層,當(dāng)Web層訪問到那些需要延遲加載的數(shù)據(jù)時,由于加載領(lǐng)域?qū)ο蟮腍ibernate Session已經(jīng)關(guān)閉,將會導(dǎo)致延遲加載數(shù)據(jù)異常。因此Spring專門提供了一個OpenSessionInViewFilter過濾器,它的主要功能是使每個請求過程中綁定一個Hibernate Session,即使最初的事務(wù)已經(jīng)完成了,可以在Web層進(jìn)行延遲加載的操作。注意:對小型系統(tǒng)來說,使用OpenSessionInViewFilter確實可以降低延遲加載所引發(fā)的各種問題,使Service層代碼更易開發(fā)和維護(hù),但是對大型且高并發(fā)的應(yīng)用來說,強(qiáng)烈建議不要使用OpenSessionInViewFilter。因為OpenSessionInViewFilter會讓每個Web請求線程都綁定一個Hibernate的Session。知道Web請求處理時才會釋放。這極大的影響了系統(tǒng)新能。
4、DAO層設(shè)計
為了增加代碼復(fù)用率,強(qiáng)烈建議使用接口、基類和泛型來定義。詳情見2.2.基類BaseDao<T>通過泛型方式允許子類Dao指定操作的實體類,以便簡化常用的數(shù)據(jù)操作方法。同時,在BaseDao注入了一個HibernateTemplate,這樣子類只要打上@Repository的注解就自然擁有HibernateTemplate成員變量了,無須各自聲明。BaseDao的構(gòu)造方法通過Java反射機(jī)制自動解析出子類T鎖對應(yīng)的類型,以便HibernateTemplate直接利用這個信息進(jìn)行數(shù)據(jù)訪問操作。
5、查詢接口方法的設(shè)計
DAO層除了CRUD的數(shù)據(jù)操作之外,另外一個重要的操作就是根據(jù)查詢條件執(zhí)行數(shù)據(jù)查詢,所有ORM框架都允許用戶動態(tài)綁定參數(shù)確定查詢條件。查詢條件的數(shù)目往往是不固定的。因此實體DAO定義帶參數(shù)的查詢方法一般有:
每一個條件項參數(shù)對應(yīng)一個入?yún)ⅰist<T> findOrder(String hql,Date starttime,Date endtime,int deptId);這種方法優(yōu)點(diǎn)是含義清晰,可讀性強(qiáng),內(nèi)部邏輯簡單,但是接口穩(wěn)定性差,并且如果查詢條件項過多,整個實體DAO類會顯得很臃腫笨重。
使用數(shù)組傳遞條件項參數(shù)。List<T> findOrder(String hql,Object[] params);這種方法的確定是可讀性不強(qiáng),調(diào)用者往往需要通過查看該接口的Javadoc才能正確使用。
使用JDK5.0的不定參數(shù)。List<T> findOrder(String hql,Object... params);
將查詢條件項參數(shù)封裝成對象。List<T> findOrder(String hql,OrderObject param);OrderObject查詢條件對象封裝了hql查詢語句可能會用到的條件項參數(shù),在查詢方法內(nèi)部,開發(fā)者必須判斷查詢條件對象的屬性并正確綁定條件項參數(shù)。確定是會造成類數(shù)目的膨脹,有事甚至一個實體DAO需要對應(yīng)多個查詢條件參數(shù)類。
使用Map傳遞條件項參數(shù)。List<T> findOrder(String hql,Map params)使用這樣方式,接口方法簽名可以在條件項發(fā)生變化的情況下保持穩(wěn)定,同事通過鍵指定條件項參數(shù)名,這在一定程度上解決了接口的健壯性。
6、總結(jié)
Spring為其所支持的ORM框架提供了方面易用的FactoryBean,用以創(chuàng)建ORM框架的基礎(chǔ)設(shè)施。Spring通過模板類在不損失框架功能的情況下大大降低了使用這些ORM技術(shù)的難度。此外Spring允許用戶使用原生的API來構(gòu)造DAO。使用原生API時,Spring能夠保證用戶獲取到事務(wù)綁定的資源,Spring的事務(wù)管理機(jī)制同樣有效。
Spring對Hibernate所提供的支持應(yīng)該是最豐富的。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。