<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-4  評論-1  文章-0  trackbacks-0
      2009年4月4日
         摘要: 原文:http://www.hibernate.org/43.html  問題  在一個典型的(Web)應用中常見的一個問題是在主要的邏輯動作完成之后渲染頁面,同時,因為邏輯動作的完成,Hibernate Session 已被關閉,數(shù)據(jù)庫事務也已結束。如果你在你的 JSP 中(或者其它視圖渲染機制)訪問已被 Session 加載的 Detached Object 的...  閱讀全文
    posted @ 2009-04-04 21:45 阿里 閱讀(922) | 評論 (0)編輯 收藏
      2009年3月14日

    本文的主要內(nèi)容是對 Grails 1.1 中 PetClinic-MVC 實例的代碼分析。這個實例主要驗證了如何在非 Grails 的項目中使用 GORM。此外也演示了 Spring MVC 2.5 的一些用法。本文假設大家對 Spring、Spring MVC、Groovy 和 Grails 有著初步的了解。OK, let's go!

    Domain 層

    目前 Grails 只提供了在普通 Spring 應用中獨立使用 GORM 的方法(現(xiàn)在 Groovy 和 Grails 已是 SpringSource 旗下的產(chǎn)品了,自然要首先對自家產(chǎn)品提供支持)。不過相信以后在其它 Java EE 框架中也可獨立使用 GORM。

    在 Grails 以外使用 GORM,只需在 Domain 類上使用 grails.persistence.Entity 注釋即可。其它的就像在 Grails 中的一樣。

    在配置方面也很簡單,只要使用 <gorm:sessionFactory ... /> 即可。詳細請見 Grails 的 PetClinic,這里就不拗述了。

    Controller 層

    同 Domain 層一樣,Controller 層也全部使用 Groovy 實現(xiàn)。主要是因為 GORM 的大部分方法都是動態(tài)的。

    1. ClinicController: ClinicController 實現(xiàn)了 InitializingBean 接口。這個接口只有一個方法 afterPropertiesSet。這個方法會在 Bean 完成屬性設置之后執(zhí)行。PetClinic 用這個方式實現(xiàn)了類似 Grails 中 BootStrap 的部分功能。在這個方法中我們可以看到 GORM 中的 save() 方法和 addTo* 動態(tài)方法都是可用的。

       1public void afterPropertiesSet() {  
       
    2.     if (!Speciality.count()) {  
       
    3.         def rad = new Speciality(name: "radiology").save()  
       
    4  
       
    5.         new Vet(firstName: "Linda", lastName: "Douglas").  
       
    6.             addToSpecialities(sur).save()  
       
    7  
       
    8.   
       
    9.         ['dog''lizard''cat''snake''bird''hamster'].each {  
      
    10.             new PetType(name: it).save()  
      
    11.         }  
      
    12.     }  
      
    13. } 


    可能有人會問,afterPropertiesSet() 這個方法的作用就是增加一些預定義的數(shù)據(jù),為什么不使用構造函數(shù)來實現(xiàn)。實際上,在本例中,afterPropertiesSet() 的作用的確可以用構造函數(shù)來實現(xiàn)(經(jīng)過測試)。至于作者是出于什么目的而選擇了實現(xiàn) InitializingBean 接口我也說不好。

    ClinicController 的其它部分就是一些簡單的不能再簡單的 Http 請求處理函數(shù)了。需要說明的一點是 @RequestMapping 中的值代表了請求的 URL,這個是不用帶后綴的,也就是說 ".do" 是多余的。

    2. AddPetForm:

           在 AddPetForm 類的級別上有三個注釋,分別是 @Controller, @RequestMapping 和 @SessionAttributes。@Controller 不用多說,作用是這個類聲明為一個 Spring Controller,并添加到 Context 中。下面介紹一下 @RequestMapping 和 @SessionAttributes 的功能:

    • @RequestMapping 可以定義處理請求的路徑和方法類型,即可放在類聲明上,也可放在方法聲明上。在 AddPetForm 中,類和方法上都有 @RequestMapping,類上的 @RequestMapping 用來定義請求路徑。兩個 @RequestMapping 的方法分別負責處理 get 請求和 post 請求。但我認為更好的方式是在一個 Controller 類中定義多個處理請求的方法,就像 Grails 的 Controller 那樣。需要注意的是方法上面的 @RequestMapping 上面的值并不會覆蓋類上的 @RequestMapping 中的值。
    • @SessionAttributes 中的值代表了 org.springframework.ui.Model 中應該被設置為 Session 范圍的變量。在 Spring MVC 應用中,這些變量往往是起到 ActionForm(Struts) 或 CommandObject(Spring MVC) 的作用。之所以要將表單對象放在 Session 中,是為了使其能夠在表單顯示和之后的表單提交這樣過程中不丟失。@SessionAttributes 的這種用法是源于 Spring MVC 2.0 AbstractFormController 的 SessionForm 模式。

      實際上,使用 @SessionAttributes 是很成問題的,有時是不可接受的。考慮以下場景:在 PetClinic 應用中,新建兩個 Owner,然后為這兩個 Owner 都添加新的 Pet。注意,只要顯示出來 Add Pet 的頁面即可。這時,這兩個頁面的 URL 應該是 addPet.do?ownerId=num1 和 addPet.do?ownerId=num2 。這時將先打開的表單 提交 ,假設是 num1 的那個。你會發(fā)現(xiàn)你 實際上是為 num2 Owner 添加了一個 Pet。

      這個問題的原因其實是很簡單的,我就不解釋了。從上面這個事實來看,@SessionAttributes 的缺點還是比較明顯。是否采用這種方式還要看這個問題對你的應用的影響是否是致命的了。Spring MVC 有必要改進一下,像 Seam 那樣可以很方便的使用 Conversation 是解決問題的一個好辦法。(當然也可以使用 hidden 域來保存 id)。

      Spring MVC 之所以要使用這種有較明顯缺陷的方式的原因是要使用 Spring MVC 的表單數(shù)據(jù)綁定功能。由于目前還沒有找到更好的方式,所以只能使用 @SessionAttribute 了。這一塊還是 Spring MVC 的一個短板,需要在新版本中改進。

    除此以外,AddPetForm 中還有兩個特殊的方法,一個是注釋了 @ModelAttribute 的方法;另一個是注釋了 @InitBinder 的方法。下面分別介紹一下:

    • @ModelAttribute 可以用在方法上,也可以用在形參上。如果放在方法上,那它會在進入請求處理方法是準備一些數(shù)據(jù),作用和 SimpleFormController 的 referenceData() 一樣。@ModelAttribute 的這種用法可能會讓人聯(lián)想到 Seam 中的 @Factory。但被 @ModelAttribute 注釋的方法只會在同一個 Controller 中被注釋了 @RequestMapping 的方法調(diào)用之前被調(diào)用,而 @Factory 方法則是全局的。

      你可以在 setupForm 方法中向 request 或 session 中設置一些需要顯示在頁面上的數(shù)據(jù),但是如果只放在 request 里的話,在表單驗證發(fā)生時,數(shù)據(jù)便會丟失;放在 session 缺點自不必多說。在 Spring Web Flow 新加入的 flow 和 conversation 等新的 scope 無法很容易地在 Spring MVC 中使用的情況下,使用 @ModelAttribute 無疑是更好的選擇。并且使用 @ModelAttribute 可以在多個 @RequestMapping 方法之間實現(xiàn)代碼的重用。

    • @InitBinder 適用于注冊只屬于本 Controller 的屬性編輯器。但在 AddPetForm 中,@InitBinder 方法只是告訴 Spring MVC,路徑為(<form: input path="id" />) id 的值不要使用屬性編輯器。不過頁面里也壓根沒有 路徑為 id 的值。所以,我覺得這個又是一個多余的代碼。(我試過將 @InitBinder 方法注釋掉,對程序沒有影響)

    Controller 層中兩個特殊的類:ClinicBindingInitializer 和 PetTypeEditor

    • ClinicBindingInitializer 的作用是注冊全句的屬性編輯器
    • PetTypeEditor 是用于處理 PetType 類型數(shù)據(jù)綁定的屬性編輯器。對于像 PetType 這樣的實體之間的關聯(lián)屬性,恰當?shù)厥褂脤傩跃庉嬈骺梢院喕绦虻拈_發(fā)。 (不知 Grails 是否實現(xiàn)了一個動態(tài)的屬性編輯器,用于關聯(lián)屬性的數(shù)據(jù)綁定)

     

    配置

    1. applicationContext.xml

            applicationContext 中大部分都是常見的 Spring 配置。特殊一點的配置除了 <gorm:sessionFactory ... /> 以外,還有 Hibernate StatisticsService JMX 的配置。

    2. dispatcher-servlet.xml

            Spring MVC 配置文件(也是一個 Spring 的配置文件)的默認名是 dispatcher-servlet.xml。

            從上至下,第一個配置表明哪個 Package 下的 Class 使用了 Spring 的 @Controller 注釋。這樣 Spring 容器在啟動的時候會自動掃描其下的 Class,將加注了 @Controller 注釋的類加入到 Spring 的容器中。

            第二個配置 DefaultAnnotationHandlerMapping HandlerMapping 接口的一個最常用的實現(xiàn)類。用于映射 Handler 和請求路徑之間的關系。通過這樣的配置,Controller 中的 @RequestMapping 中的路徑值就可以真正地和 Http 請求對應起來。HandlerMapping 的另外一個常用的實現(xiàn)類是 ControllerClassNameHandlerMapping

            第三個配置 AnnotationMethodHandlerAdapter 的作用是使處理請求的 Handler 能夠真正的具有處理請求的能力而提供一些服務,包括為請求參數(shù)綁定應用相應的屬性編輯器(通過注冊 webBindingInitializer 實現(xiàn))。

     

    ==============================結束的分割線==============================

    寫到這里,PetClinic-MVC 中值得分析學習的代碼都提到了。PetClinic-MVC 是一個很小的應用,但是其中演示了 GORM 在普通 Spring 中的應用和 Spring MVC 2.5 的使用。細看的話還是能學到不少東西的。我所寫的只是我的理解,難免會有一些不足和錯誤,歡迎糾正。

    posted @ 2009-03-14 12:33 阿里 閱讀(1614) | 評論 (1)編輯 收藏
      2008年7月16日
    SessionFactory.getCurrentSession() 是 Hibernate 應用獲取 Session 的常用方法。在調(diào)用該方法時,Hibernate 會從 interface CurrentSessionContext 獲取當前的 Session,這是Hibernate 在不同組件中傳遞 Session 的方法。

    CurrentSessionContext 有三個實現(xiàn),分別是 ThreadLocalSessionContext、JTASessionContext 和 ManagedSessionContext。ThreadLocalSessionContext 將 Session 與當前線程綁定,是使用較多的一種方案;JTASessionContext 將 Session 與 JTA 事務綁定,在 JTA 環(huán)境中使用;ManagedSessionContext 使應用可以通過 bind() 和 unbind() 方法控制 Session 的綁定,主要在有 Conversation 的應用中使用(如果使用 ManagedSessionContext,開發(fā)人員要做的事情還是很多的)。CurrentSessionContext 實現(xiàn)的選擇可以通過 hibernate.current_session_context_class 來配置。

    另一種更常見的創(chuàng)建 Session 的方法是 openSession()。openSession() 與 getCurrentSession() 有何不同和關聯(lián)呢?在 SessionFactory 啟動的時候,Hibernate 會根據(jù)配置創(chuàng)建相應的 CurrentSessionContext,在 getCurrentSession() 被調(diào)用的時候,實際被執(zhí)行的方法是 CurrentSessionContext.currentSession() 。在 currentSession() 執(zhí)行時,如果當前 Session 為空,currentSession 會調(diào)用 SessionFactory 的 openSession。所以 getCurrentSession() 對于 Java EE 來說是更好的獲取 Session 的方法。

    再說 ManagedSessionContext,它提供了更靈活的綁定 Session 的方式,但是使用起來去不簡單。在 Hibernate 的 CaveatEmptor 實例中有關于使用 ManagedSessionContext 的例子,但更好的選擇是使用 Seam Framework。
    posted @ 2008-07-16 15:48 阿里 閱讀(1543) | 評論 (0)編輯 收藏
      2008年6月14日

    本文將簡單談談我對 EJB 3.0 的兩種 Persistence Context 和 Seam-managed Persistence Context 的不同點的理解、所要解決的問題和我自己所疑惑的問題。

    EJB 3.0 (JPA) 的 Persistence Context

        大家在使用 EJB 3.0 的時候會注意到 EJB 3.0 中的容器管理 Persistence Context 有兩種類型,一種是 Transaction,另一種是 Extended。這是一個較 Hibernate 的 Session 所沒有的概念,Session 沒有兩種不同的類型,而且最重要的是 Session 不是容器管理的,這里的容器指的是 App Server 容器。這里暫時不談論 Persistence Context 與 Session 之間的異同,主要談談兩種 Persistence Context 之間的不同。學過 ORM 的同學都知道,當 Persistence Context 是打開狀態(tài)的時候,Model 就處于被管理的狀態(tài)中;當 Persistence Context 關閉之后,Model 就處于了 Detached 狀態(tài)。

        上面這些特性對于 Transaction 或 Extended 的 Persistence Context 都是一樣的,不同的地方在于 Persistence Context 何時被打開關閉。由于絕大多數(shù)情況下 Persistence Context 是被容器管理的(如果你不嫌累也可以自己控制 Persistence Context),所以在 EJB 3.0 應用中看不到打開或關閉 Persistence Context 的代碼(Spring + Hibernate 的應用也同樣如此,Hibernate Session 的管理工作可以交給 Spring 來做)。


        其實,Transaction 和 Extended Persistence Context 的不同之處也就在于容器何時打開或關閉 Persistence Context。Transaction 類型的 Persistence Context 的打開和關閉是和事務的打開和關閉是同步的。也就是說在一個事務開始之后,Persistence Context 才會開始;在事務關閉的時候,相應的 Persistence Context 也會被關閉。

       Extended 類型的 Persistence Context 的打開和關閉是和 Stateful Session Bean 的生命周期同步的,是跨越事務的。也就是說,從 SFSB 的初始化開始,直到銷毀,Persistence Context 都是存在的。你可以在事務之外執(zhí)行寫操作,但是這是并不會執(zhí)行真正的數(shù)據(jù)庫操作,寫操作只是放入了隊列,直到下一個事務,寫操作才會真正地被執(zhí)行。兩者的 不同簡單說來就是 Extended Persistence Context 存在的時間更長。那為什么要有兩種不同的 Persistence Context 呢?

        當一個 Web 請求到來時,服務器會打開一個線程,這個線程可能會調(diào)用一個事務方法,這是一個事務便開始了,當這個請求結束時,線程關閉,事務也隨之結束。由于 Transaction 類型的 Persistence Context 的生存周期是在事務范圍之內(nèi)的,所以一個 Web 請求的結束也意味著相應的 Persistence Context 的關閉。由于多數(shù) Web 應用在一次 Web 請求內(nèi)即可完成一個獨立的操作,所以大部分情況下 Transaction 的 Persistence Context 是適用的。但是對于一些復雜的應用,一次操作需要跨越多次請求。這種情況下,如果依舊使用 Transcation 的 Persistence Context,由于每次請求結束后,相應的 Persistence Context 都被關閉,相應的 Model 也就變?yōu)?Detached 狀態(tài)。如果接下來的請求仍然需要這些已經(jīng)變?yōu)?Detached 狀態(tài)的 Model 就需要重新 load,使用 merge() 方法來持久化。稍有不適就會產(chǎn)生 LazyInitializationException 和 NonUniqueObjectException。同時,這也提高了操作的復雜程度。

        如果使用 Extended Persistence Context 就能解決這些問題。由于 Extended Persistence Context 的生命周期是與 SFSB 的生命周期同步的,所以只要多次請求調(diào)用的都是同一個 SFSB 中的方法,有多少次的請求,Persistence Context 總是同一個,其中的 Model 也始終是被管理的。很好地解決了 Persistence Context 在線程之間傳遞的問題,也不會有 LazyInitializationException 和 NonUniqueObjectException 問題的發(fā)生。

    Seam-managed Persistence Context

        EJB 3.0 容器管理之下的 Persistence Context 很不錯,能解決很多問題,但是還是有些問題無法解決。Seam 很強大,如果有些問題 EJB 容器解決不了了,沒關系,把 Persistence Context 交由 Seam 來管理就 OK 了。那 Seam 都能解決哪些 EJB 不能解決的問題呢?先考慮下面兩個問題:

    1. Extended Persistence Context 雖然可以跨越多個事務,但是每個事務照舊調(diào)教不誤,這對于想在想讓整個操作作為一次事務的話,該如何去做
    2. 如果一個業(yè)務的一組請求只是調(diào)用同一個 SFSB 的話,那么 EJB 的 Extended Persistence Context 可以在線程之間傳遞,使 SFSB 的整個生命周期都使用同一個 Persistence Context。但如果業(yè)務需要調(diào)用不同的 SFSB 的話,如何在 SFSB 之間傳遞。
        對于第一個問題,由于 Seam 的 JPA 實現(xiàn)提供者是 Hibernate,而且 Hibernate 提供了一個擴展的 FlushModeType - "Manual"。通過使用這個 FlushModeType,我們可以手工控制何時執(zhí)行 flush() 操作。在 Seam 的文檔中有關于這部分的介紹 《Seam-managed persistence contexts and atomic conversations 》。文檔中使用了一段簡單的代碼展示 Seam 如何實現(xiàn)所謂的 "atomic conversations"(關于代碼的內(nèi)容我就不介紹了,大家通過我提供的鏈接來瀏覽 Seam 的文檔)。通過這種方式,事務貌似是跨越了整個事務,但我認為 SFSB 中除了調(diào)用 flush() 的方法以外的其它方法不是事務的。其實也沒有必要,因為這些方法并沒有執(zhí)行數(shù)據(jù)庫操作,所以沒有必要使用事務。當然,如果是樂觀事物的話,使用了對性能影 響也不大(這只是我的一點淺薄的理解,歡迎指出錯誤)。只有最后的調(diào)用了 flush() 的方法有事務的必要。

        這就引發(fā)了一個令我不解的問題。請先看這篇文章《Extended Persistence Context in Stateful Session Beans 》。在這篇文章介紹了如何只使用 EJB 3.0 去解決“問題1”。文中的 SFSB 的默認事務屬性是 "NOT_SUPPORTED",也就是說這個 SFSB 中的方法默認不是事務的。只有最后的調(diào)用 flush() 的方法使用了 "REQUIRED" 的事務屬性去覆蓋默認設置。也就是最后的方法是事務的,其它的不是。這和 Seam 所做的有區(qū)別嗎?感覺沒有區(qū)別。但我認為像 Gavin King 這樣的大牛絕不會做無用功的,那問題就是 Seam 實現(xiàn) "atomic conversations" 的內(nèi)部細節(jié)到底是什么呢?歡迎大家回答這個問題。

        對于第二個問題,可以通過使用 Seam-Managed Persistence Context 來解決。Seam-manged Persistence Context 需要在 components.xml 文件中進行配置,并使用 @In 注入到 Seam 的組件中。由于 Seam 是一個比較新的框架技術,所以關于 Seam 是如何使 Persistence Context 在組件中傳遞并沒有詳細的介紹。應該只是聲明,然后透明地使用即可。在一個 jBPM 流程中被使用到的 Seam 組件,其中的 Persistence Context 應該是可以很容易地被傳遞。(本不應該使用不確定的和模糊的詞語,但無奈現(xiàn)在關于 Seam 的文章資料還是有限,所以我也沒有找到關于 Persistence Context 在組件之間調(diào)用的例子)

    結束語:這篇文章解釋的問題不多,不過都是我自己的理解。可能有錯誤 的地方,歡迎大家指出。同時,又有一些新問題產(chǎn)生了,應該可以通過閱讀 Seam 提供的例子和源代碼得到解釋。但 Seam 的例子只看過三個,更多的還沒有看。看過的 Seam 的源代碼更可以忽略不計。繼續(xù)努力吧!!
    posted @ 2008-06-14 21:59 阿里 閱讀(1477) | 評論 (0)編輯 收藏
    僅列出標題  
    主站蜘蛛池模板: a在线观看免费网址大全| 美女视频黄a视频全免费网站色| 亚洲А∨精品天堂在线| 亚洲男同gay片| 台湾一级毛片永久免费| 免费一级毛片一级毛片aa| 亚洲私人无码综合久久网| 中文字幕不卡免费视频| 伊人亚洲综合青草青草久热| 亚洲一区二区三区免费在线观看| 99久9在线|免费| 亚洲性无码av在线| 日韩精品无码区免费专区| 国产精品亚洲综合久久| 好爽又高潮了毛片免费下载| 国产成人亚洲综合色影视| 3344在线看片免费| 亚洲国产精品婷婷久久| 1000部夫妻午夜免费| 亚洲精品无码国产片| 亚洲VA综合VA国产产VA中| 国产色无码精品视频免费| 亚洲四虎永久在线播放| 无码乱肉视频免费大全合集| 亚洲乱亚洲乱妇24p| 亚洲婷婷国产精品电影人久久| a级毛片无码免费真人久久| 亚洲精品午夜在线观看| 免费电影在线观看网站| 免费在线观看一区| 免费无码黄动漫在线观看| 色屁屁在线观看视频免费| 亚洲精品无码成人片久久 | 国产午夜亚洲精品不卡| 国产成人精品亚洲精品| 99免费在线观看视频| 亚洲熟妇久久精品| 亚洲精品你懂的在线观看| 中文字幕无码成人免费视频| jizz免费观看视频| 亚洲国产精品乱码在线观看97 |