【Java EE 學習 54】【OA項目第一天】【SSH事務管理不能回滾問題解決】【struts2流程回顧】

1、SSH整合以後事務問題和總結java

  1.引入問題:DAO層測試git

    假設將User對象設置爲懶加載模式,在dao層使用load方法。github

     

    注意,註釋不要放開。web

    使用以下的代碼塊進行測試:spring

    會報錯:no session。sql

    

    爲何會沒有session呢,由於在代碼apache

User user=(User) hibernateTemplate.load(User.class, id);

    執行完成以後session就已經關閉了。緩存

  2.Service層測試安全

    (1)Service層代碼:服務器

    

      DAO層代碼:

     

      測試代碼:

    

    運行結果:

    

    出現的錯誤結果和上面徹底相同。

    (2)解決錯誤

      將DAO層中的代碼註釋去掉或者將Service中的代碼註釋去掉。

      註釋的代碼做用是打印結果,只是一個System.out.println方法的執行;雖然如此,程序運行再也不有問題。

      

  3.緣由分析

    (1)爲何測試DAO不管怎麼測試都會報出異常?

       由於DAO層調用完成getUserById方法以後session就立刻關閉了,因此執行下一句代碼的時候即便是打印輸出的代碼也會報錯。

    (2)爲何測試Service的時候若是沒有去掉註釋的話,就會出錯?

       由於去掉註釋的話,Service層調用完成getUserById方法以後Session就會關閉,效果和在DAO層是徹底相同的,因此結果和在DAO層是徹底相同的。報錯的信息徹底相同。

    (3)爲何Service層去掉註釋以後就不報錯了?

      Service層去掉註釋以後因爲方法尚未退出,因此會將數據保存到User對象中;因此數據已經保存到了內存中,這樣就不會報錯了。

    (4)在DAO層去掉註釋以後會不會報錯?

      去掉DAO層的註釋以後的運行結果:

      

      結果是沒有報錯,爲何,DAO層調用完成查詢的方法以後不是會當即關閉session嗎?

        結果是沒有關閉Session,緣由是在Service層調用的方法,該方法具備事務,並且該事務的範圍擴展到了DAO層。最根本的緣由是在Spring配置文件中的配置:

      

      propagation屬性值是默認的,因此在Service層中方法執行的時候,執行的全部方法都將會帶有事務,直到方法結束,事務也會隨之結束,所以DAO層纔沒有當即結束事務(關閉session)。

  4.總結SSH整合以後事務管理的範圍

    (1)若是當前執行的方法沒有事務環境,當執行完成this.hibernateTemplate中的方法以後session當即關閉。

    (2)若是當前執行的方法有事務環境,當事務環境的方法被調用完成以後session關閉。

  5.經過以上的分析和總結能夠獲得若是直接在Action中調用Service層中的方法,若是出現異常,確定不能回滾,例以下面中的測試代碼:   

     

    很明顯,這裏有/0的異常,因此若是事務可以回滾,則不會發出insert的sql語句。可是結果倒是:

     

    因此事務回滾失敗了。緣由就是Service對象中的每個方法執行完成以後都會當即關閉session,事務也隨之消失。相同Service中的方法調用屢次或者相同Service中的不一樣方法執行的時候必定不會在同一個事務中。

2、解決SSH整合以後的事務問題

  解決方法就是使用OSIV模式(Open Session In View),即在MVC中的View層就開啓事務,這樣就擴展了事務的範圍。

  只是在web.xml文件中加上以下的配置便可:

    <!-- 使用OSIV模式解決事務回滾問題,只須要添加一個監聽器就能夠了 -->
    <filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>

  也就是說只是增長了一個過濾器而已,應當注意該過濾器放置的位置應當在下面的配置上面:

<filter>
        <filter-name>strutsFilter</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>strutsFilter</filter-name>    
        <url-pattern>*.action</url-pattern>
    </filter-mapping>

  不然添加的過濾器不生效。完整的web.xml文件配置以下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app version="3.0" 
 3     xmlns="http://java.sun.com/xml/ns/javaee" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 5     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 6     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
 7     
 8     
 9         <!-- 使用OSIV模式解決事務回滾問題,只須要添加一個監聽器就能夠了 -->
10     <filter>
11         <filter-name>OpenSessionInViewFilter</filter-name>
12         <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
13     </filter>
14     <filter-mapping>
15         <filter-name>OpenSessionInViewFilter</filter-name>
16         <url-pattern>*.action</url-pattern>
17     </filter-mapping>
18     
19     <filter>
20         <filter-name>strutsFilter</filter-name>
21         <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
22     </filter>
23     <filter-mapping>
24         <filter-name>strutsFilter</filter-name>    
25         <url-pattern>*.action</url-pattern>
26     </filter-mapping>
27     
28 
29     
30     <listener>
31         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
32     </listener>
33     <context-param>
34         <param-name>contextConfigLocation</param-name>
35         <param-value>classpath:spring/applicationContext.xml</param-value>
36     </context-param>
37     
38   <welcome-file-list>
39     <welcome-file>index.jsp</welcome-file>
40   </welcome-file-list>
41 </web-app>
web.xml

  最後,使用OSIV模式應當注意的事項:

    1.使用OSIV模式以後,sessio的打開被提早了,session的關閉被延後了,這樣就解決了懶加載引發的異常的問題。

    2.兩個過濾器,OSIV的過濾器必須在struts2以前。

  使用OSIV模式的缺點:

    由於Session的關閉被延遲了,因此hibernate的一級緩存在session中,因此會致使大量的緩存數據長期保存在了內存中。

3、Struts2流程回顧

  1.啓動服務器的時候幹了兩件事情。

    

      * dispatcher = init.initDispatcher(config);該句代碼加載了各類各樣的配置文件。

      * init.initStaticContentLoader(config, dispatcher); 該句代碼完成了靜態注入。

  2.當過濾器攔截到一個請求的時候作了什麼事情

    查看doFilter方法中的源代碼。

    (1)建立AciontContext對象。

      建立ActionContext對象的同時會同時建立ValueStack對象,並且建立ValueStack對象在前,建立ActionContext對象在後。

    兩個對象同時建立,並且兩個對象維護同一個Map對象,緣由是建立ActionContext的時候使用的參數是ValueStack對象的context成員變量。

   經過代碼ActionContext.setContext(tx);便可以將ActionContext放置到ThreadLocal中了,這樣數據就安全了,下面是代碼追蹤。

    (2)建立ActionProxy對象

    init方法中執行了建立了對應的Action和全部的攔截器。

    

    最後在invocation的invoke方法中執行全部的攔截器、執行當前請求的action、執行結果集。

    

4、Struts2的完整流程圖

  

 

最後附上項目源代碼:https://github.com/kdyzm/day53_ssh_oa

相關文章
相關標籤/搜索