Spring整合Hibernate時(shí),,主要做了兩件事:提供事務(wù)級(jí)session和聲明式的事務(wù)控制。 在較早的Hibernate中,,對(duì)于session的管理一般是one-session-per-operation的方式,,即一次具體操作一個(gè)session。 Spring為了解決這個(gè)問(wèn)題,,引入了HibernateTemplate類,。 先來(lái)看看它的文檔中一段很有意思的話: NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can also be coded in plain Hibernate style. Hence, for newly started projects,consider adopting the standard Hibernate3 style of coding data access objects instead, based on SessionFactory.getCurrentSession().(Spring's LocalSessionFactoryBean automatically supports Spring transaction management for the Hibernate3 getCurrentSession() method.)作者說(shuō):在新開(kāi)始的工程,可以考慮用標(biāo)準(zhǔn)的Hibernate3的編碼方式作為HibernateTemplate的替代,。因?yàn)镠ibernate3提供的SessionFactory.getCurrentSession()已經(jīng)取代了以往那種每次操作都o(jì)pen一個(gè)新Session的方式,,同時(shí)Spring的LocalSessionFactoryBean自動(dòng)支持Hibernate3的getCurrentSession()的事務(wù)管理。也就是說(shuō),,如果不用HibernateTemplate這咱Spring的專有API,,而只用Hibernate3,我們一樣可以受用Spring的事務(wù)管理。 來(lái)詳細(xì)地看看HibernateTemplate,,因?yàn)樗吘购?jiǎn)化了Hibernate的操作,,但是在有些情況下,我們應(yīng)該使用Hibernate而不是用HibernateTemplate,。根據(jù)HibernateTemplate的文檔注釋,,它做了兩件事:1.簡(jiǎn)化了Hibernate的數(shù)據(jù)訪問(wèn)編碼;2.自動(dòng)地將HibernateExceptions轉(zhuǎn)化為Spring的異常體系中的DataAccessExceptions(這是一個(gè)unchecked exception). HibernateTemplate實(shí)現(xiàn)第一點(diǎn),,是通過(guò)回調(diào)來(lái)實(shí)現(xiàn)的,它的核心方法execute(): public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException
{ //這個(gè)Session是受Spring事務(wù)管理的 Session session = getSession(); //這個(gè)是怎么回事,,還要再仔細(xì)看看,,我想它應(yīng)該是關(guān)系到Session在這個(gè)操作里操作完是否關(guān)閉的關(guān)鍵 boolean existingTransaction = SessionFactoryUtils .isSessionTransactional(session, getSessionFactory()); FlushMode previousFlushMode = null; try { previousFlushMode = applyFlushMode(session, existingTransaction); enableFilters(session); //在默認(rèn)情況下,不把Sessin暴露給用戶 Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy (session)); //exposeNativeSession默認(rèn)值為false //這里是真正涉及到Hibernate操作的地方 Object result = action.doInHibernate(sessionToExpose); flushIfNecessary(session, existingTransaction); return result; } catch(...){ //將Hibernate代碼拋出的HibernateException,,SQLException //轉(zhuǎn)化為 DataAccessExceptions,,如果有運(yùn) 行時(shí)異常,將其拋出 } finally { if (existingTransaction) { disableFilters(session); if (previousFlushMode != null) { session.setFlushMode(previousFlushMode); } } else { // Never use deferred close for an explicitly new Session. if (isAlwaysUseNewSession()) { //這里的默認(rèn)值是false,所以此次操作結(jié)束后,,session不會(huì)在此關(guān)閉 SessionFactoryUtils.closeSession(session); } else { //沒(méi)有硬性關(guān)閉Session,這是區(qū)別于Hibernate3以前版本的地方 SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory()); } } } } 真正的數(shù)據(jù)操作是在HibernateCallback action中實(shí)現(xiàn)的,,為了執(zhí)行action中的操作,需要一個(gè)Session,這個(gè)Session是在execute()方法內(nèi)部獲得(不一定是新產(chǎn)生的)并傳入的,。另外,,在操作執(zhí)行完之后,這個(gè)Session沒(méi)有硬性關(guān)閉,,而是交由SessionFactoryUtils來(lái)決定是否立即關(guān)閉還是延遲關(guān)閉,。有時(shí)間再看看SessionFactoryUtils .closeSessionOrRegisterDeferredClose()具體做了些什么。
用HibernateTemplate比起直接用Hibernate編碼簡(jiǎn)潔了很多,。但是,,作者在文檔中寫(xiě)到:The major advantage is its automatic conversion to DataAccessExceptions, the major disadvantage that no checked application exceptions can get thrown from within data access code.因?yàn)榉忾]得太好了,我們根本無(wú)法干預(yù)HibernateTemplate的方法內(nèi)部,,因此我們 不能拋出檢查型的應(yīng)用異常,。如果我們想在某個(gè)方法的內(nèi)部在某個(gè)條件下拋出自定義的應(yīng)用異常,就要用Hibernate直接編碼了,,這是不應(yīng)該用HibernateTemplate的情況,。 作者在文檔中還寫(xiě)到:It can be used within a service implementation via direct instantiation(實(shí)例)with a SessionFactory reference, or get prepared in an application context and given to services as bean reference. 為了使用 HibernateTemplate,我們需要一個(gè)SessionFactory,因?yàn)槭褂肏ibernateTemplate時(shí)需要獲取Session,而Session是從SessionFactory獲取的,。我們可以在應(yīng)用配置文件中,,根據(jù)已配置的SessionFactory配置一個(gè)HibernateTemplate,或者在程序中要用時(shí)再根據(jù)已配置好的SessionFactory來(lái)產(chǎn)生一個(gè)HibernateTemplate。Spring提供了一個(gè)可配置的SessionFactory的工廠類,,用以向容器暴露一個(gè)單例化的SessionFactory:LocalSessionFactoryBean,。這個(gè)類的源碼也很有意思,還要繼續(xù)看一下,。 為了進(jìn)一步簡(jiǎn)化Hibernate的操作,,Spring提供了一個(gè)用于DAO的基類HibernateDaoSupport:This base class is mainly intended for HibernateTemplate usage。這個(gè)類只有唯一的成員變量private HibernateTemplate hibernateTemplate,。但是我在想,,Spring是不是做的太過(guò)分了?包裝得太好了,?,? 下邊附上HibernateTemplate的一般使用方法:
hibernateTemplate的常用方法: Ø void delete(Object entity):刪除指定持久化實(shí)例 Ø deleteAll(Collection entities):刪除集合內(nèi)全部持久化類實(shí)例 Ø find(String queryString):根據(jù)HQL查詢字符串來(lái)返回實(shí)例集合 Ø findByNamedQuery(String queryName):根據(jù)命名查詢返回實(shí)例集合 Ø get(Class entityClass, Serializable id):根據(jù)主鍵加載特定持久化類的實(shí)例 Ø save(Object entity):保存新的實(shí)例 Ø saveOrUpdate(Object entity):根據(jù)實(shí)例狀態(tài),,選擇保存或者更新 Ø update(Object entity):更新實(shí)例的狀態(tài),要求entity是持久狀態(tài) Ø setMaxResults(int maxResults):設(shè)置分頁(yè)的大小 HibernateDaoSupport: Spring為Hibernate的DAO提供工具類:HibernateDaoASupport,。該類主要提供如下兩個(gè)方法,,方便DAO的實(shí)現(xiàn): 1、public final HibernateTemplate getHibernateTemplate() 2,、public final void setSessionFactory(SessionFactory sessionFactory) 其中setSessionFactory方法用來(lái)接收Spring的ApplicationContext的依賴注入,,可接收配置在Spring的SessionFactory實(shí)例,getHibernateTemplate方法則用來(lái)更具獲得的SessionFactory產(chǎn)生Session,,最后生成HibernateTeplate來(lái)完成數(shù)據(jù)庫(kù)訪問(wèn),。
看到這些的時(shí)候似乎好像明白了以些,HibernateDaoSupport此類其實(shí)并不做太多的事情,,它只有兩個(gè)方法一個(gè)是獲得getHibernateTemplate()和setSessionFacotry()。就像我們?cè)谂渲梦募信渲玫哪莻€(gè)sessionFactory屬性,。而getHibernateTemplate()方法就是常用的save,、delete等CRUD基本操作。
HibernateTemplate 用于持久層的訪問(wèn),,該模板無(wú)需打開(kāi)session及關(guān)閉Session,。它只要獲得SessionFactory的引用,就可以打開(kāi)Session,,并在持久化訪問(wèn)結(jié)束后關(guān)閉Session,程序開(kāi)發(fā)只需要完成持久曾邏輯,,通用的CRUD操作由HibernateTemplate完成.
其實(shí)Spring+hibernate訪問(wèn)數(shù)據(jù)庫(kù)有以下幾種方法: 1、 注入SessionFactory 在spring配置文件中,,對(duì)Dao注入sessionFactory.比較簡(jiǎn)單,。 如: <bean id="UserInfoDao" class="com.hr2job.dao.impl.UserInfoDaoImpl"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> 這里的sessionFacotry注入不是給類的,而是給繼承HibernateDaoSupport類的sessionFactory,,在上面源碼中可以看到,。以前寫(xiě)SSH程序的時(shí)候就是用這個(gè)的,因?yàn)槭遣恢?,這個(gè)好處就是我們不再需要關(guān)心關(guān)閉,、是否連接成功等問(wèn)題。主要是很方便,。但是這個(gè)不好就是java只支持單繼承,,所以唯一的繼承給了HibernateDaoSupport有點(diǎn)可惜。而且也沒(méi)有必要這樣做,。 2,、 注入HibernateTemplate 這種方法本質(zhì)上跟上面的sessionFacotry一樣,只不過(guò)進(jìn)行了一層包裝,,好處就是Dao中的類就不用再繼承那個(gè)HibernateDaoSuport了,,不過(guò)要先配置好HibernateTemplate: <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> 非常的方便,,我現(xiàn)在就在用這個(gè)了。其實(shí)并沒(méi)有改多少,,就是曾經(jīng)的sessionFactroy改成了hibernatemplate,。 3、 注入jdbcTemplate 這種方法適合那些不喜歡hibernate的save,delete等方法,,喜歡自己寫(xiě)的N人吧,。有時(shí)候jdbcTemplate查詢的效率會(huì)很高。這可能是跟jdbc有關(guān)吧,。 配置如下: <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 在類中set方法jdbctemplate方法就可以了,,spring中的配置跟sessionFactory基本一樣。 總的感覺(jué)還是喜歡HibernateTemplate,,原因就是好用,,不需要寫(xiě)太多的sql語(yǔ)句,不需要 類去繼承,,只要提供一個(gè)set方法,,再注入一下很方便。應(yīng)該還有很多的地方不同,,歡迎大家討論,。 |
|