1. 程式人生 > >解決no session問題的三種方式

解決no session問題的三種方式

1.get() 採用立即載入方式,而 load() 採用延遲載入;
2.get() 方法執行的時候,會立即向資料庫發出查詢語句,而 load() 方法返回的是一個代理(此代理中只有一個 OID 屬性),只有等真正使用該物件屬性的時候,才會發出 sql 語句並執行 3.如果資料庫中沒有對應的記錄 , get() 方法返回的是 null . 而 load() 方法出現異常 ObjectNotFoundException

      我在資料層中封裝了一個 load() 方法,根據使用者 Id 獲取使用者物件:

public UserModel getUserById(Long uuid) {
        return this.getHibernateTemplate().load(UserModel.class, uuid);
        //return this.getHibernateTemplate().get(UserModel.class, uuid);
    }

        當在業務層呼叫了這個方法後,獲得一個 userModel 物件,當展示使用者資訊時,就會報出 noSession 問題,

複製程式碼

public String get(){
        //報出了 org.hibernate.LazyInitializationException: could not initialize proxy - no Session異常
        UserModel temp = userEbi.get(1L);
        System.out.println(temp.getName());
        System.out.println(temp.getAge());
        return "haha";
    }

複製程式碼

報出的異常如下:

image

原因:

        這是因為資料層提供的 load() 方法具有延遲載入的特性,在呼叫 load方法時,Hibernate 不會立即執行 sql 語句,而是動態的生成一個 UserModel 的代理物件例項,這個代理物件只具有 OID,也就是 uuid 值【這個值來自於形參,而不是資料庫】,該物件的其他資訊都沒有。

這個動態代理物件所具有的特性有:

  1. 代理類物件和真實的 UserModel 物件無異,但是隻具有 OID,其他屬性均為 null,所以會比較省記憶體,這也是延遲載入的好處
  2. 當第一次訪問這個代理類物件時,呼叫器 getXxx 方法時不會出問題,Hibernate 才會初始化這個代理物件,並會自動去執行 sql 語句去查詢其資料庫中的資料,【也就是 Service 層中的同一個方法,一旦這個方法彈棧,即事務提交結束,session 被關閉,】。

       當需要這個只具有 OID 的代理物件傳遞到了業務層(如果在事務關閉session之前立馬進行二次查詢,就不會出問題),此時物件仍是一個延遲載入物件(只具有 OID),如果傳遞到了表現層(action內),此時該物件依然是延遲載入物件(但此時早在業務層,方法早已彈棧,事務就已經將 session 關閉了,一旦要進行二次查詢就會報異常, 因為 session物件已經被重新整理了,也就是連線斷開了,session 中儲存的資料早已丟失),值得一說的是在表現層使用二次查詢是比較正常的需求。

解決這個問題有三個途徑:

  • 在全域性取消延遲載入資料
  • 在區域性取消延遲載入資料
  • 將 session 的範圍擴大,擴大到表現層【此時就是 action 內 】

第一種:在全域性取消延遲載入資料,【這裡的全域性指的是某個表,並不是整個資料庫】

複製程式碼

<?xml version="1.0"?>  
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
                                       "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
    <hibernate-mapping package="com.msym.entity">  
    <!-- 取消對於 user_db 表的延遲載入屬性 -->  
     <class name="User" table="user_db" lazy="false" >  
      <id name="id">  
       <generator class="identity"/>  
      </id>  
      <property  name="password" />  
      <property  name="name" />
      <property  name="nickName" />    
      <property  name="age" />  
      <property  name="birthday" />  
     </class>  
    </hibernate-mapping>

複製程式碼

優點:簡單方便;

缺點:對於這個表,取消了延遲載入,在很多情況下會導致記憶體佔用大的問題,取出了原本不需要的資料。

第二種:在區域性取消延遲載入,【在 Service 層和 dao 層都可以區域性取消延遲載入屬性】

複製程式碼

public UserModel getUserById(Long uuid) {
        UserModel u =  this.getHibernateTemplate().load(UserModel.class, uuid);
        Hibernate.initialize(u);
        return u;

        //return this.getHibernateTemplate().get(UserModel.class, uuid);
    }

複製程式碼

優點:相比第一種,更加具有針對性,更加的靈活;

缺點:程式碼量稍稍多了一點點【但是也不要緊】。

第三種:擴大 session 的範圍,

       也就是要做到當前 session 在 Service 層的方法彈棧後不隨事務的提交而關閉,直到一次請求與響應完成才關閉。這時用到的一個技術就是 openSessionInView,將 session 與當前請求對應的執行緒繫結在一起【此 session 並非瀏覽器會話級別的 session,而是資料庫連線的 session】,這需要在 web.xml 中配置一個過濾器,這時註解的事務的任務就是開啟事務,重新整理事務;關閉事物的功能交給了 OpenSessionInViewFilter 這個類了,因為這個過濾器配置在一個,請求物件 request 最先接觸到它,請求結束時的最後一個過濾器也是它(這就是過濾器鏈了,往返要都過濾一次)。程式碼在下面:(一定要將 OpenSessionInViewFilter 配置在所有過濾器的前面)

複製程式碼

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- applicationContext物件載入僅載入一次,伺服器啟動時載入,使用web中的監聽器機制 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    
    <!-- OpenSessionInView解決noSession問題,一定要配置在核心過濾器的前面 -->
    <filter>
        <filter-name>openSessionInView</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>

        <init-param>
            <param-name>sessionFactoryBeanName</param-name>
            <param-value>sessionFactory</param-value>
        </init-param>

        <init-param>
            <param-name>singleSession</param-name>
            <param-value>true</param-value>           
        </init-param>

        <init-param>
            <param-name>flushMode</param-name>
            <param-value>AUTO</param-value>        
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>openSessionInView</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


    <!-- struts核心過濾器 -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

複製程式碼

OpenSessionInViewFilter 配置了三個引數:singleSession,sessionFactoryBeanName ,flushMode,

這幾個屬性都有其預設值,分別是,true,SessionFactory,MANUAL【手動提交事務】。

其中只是將 flushMode的預設屬性修改了,是為了防止出現 FlushModel 相關的異常。

      因為上面使用的是【org.springframework.orm.hibernate3.support.OpenSessionInViewFilter】這些屬性在其中都能找到,

image

但是如果使用的是 hibernate4.support 的話,這些屬性的位置就發生了變化,
其中:

       (1) . sessionFactoryBeanName 還是在 OpenSessionInViewFilter裡面,預設值也是 sessionFactory 如下圖:

image
       (2) . singleSession 預設值也是 true

       (3) . flushMode 屬性來自於 Session 這個介面,預設值也是MANUAL【手動提交事務】。

image

       它表示事務的提交方式,有如下幾種:

image

優點:配置簡單,

缺點:攔截了所有請求,效率不高,如果物件導航層級較多,會導致頁面的載入速度變慢,延長了 Session的生命週期,加重了伺服器的負擔。

總結:

        到最後推薦使用第二種,也就是區域性取消延遲載入特性,靈活性更好。

相關推薦

解決no session問題的方式

1.get() 採用立即載入方式,而 load() 採用延遲載入; 2.get() 方法執行的時候,會立即向資料庫發出查詢語句,而 load() 方法返回的是一個代理(此代理中只有一個 OID 屬性),只有等真正使用該物件屬性的時候,才會發出 sql 語句並執行 3.如

Java設置session超時(失效)的方式 設置session的有效時間

tag modify cli plain time web.xml ati -h value 1. 在web容器中設置(此處以tomcat為例) 在tomcat-5.0.28\conf\web.xml中設置,以下是tomcat 5.0中的默認配置: [ht

分散式鎖解決併發的實現方式

分散式鎖解決併發的三種實現方式 在很多場景中,我們為了保證資料的最終一致性,需要很多的技術方案來支援,比如分散式事務、分散式鎖等。有的時候,我們需要保證一個方法在同 一時間內只能被同一個執行緒執行。在單機環境中,Java中其實提供了很多併發處理相關的API,但是這些API在分散式場景中就無能

struts2使用session方式

1、通過上下文,從ActionContext中獲取 ActionContext actionContext = ActionContext.getContext(); Map session = actionContext.getSession(); 2、實現SessionAware介面

解決Ajax跨域請求的方式

如何解決跨域問題 什麼叫跨域: 主機、協議、埠三者有任何一個不同即為跨域 1. JSONP   JSONP是JSON with Padding的略稱。它是一個非官方的協議,它允許在伺服器端整合Script tags返回至客戶端,通過javascript call

方式解決vue中v-html元素中標籤樣式

當我們引入第三方元件或載入html元素時,想修改下樣式,就可以用以下三種方式: 一.去掉<style scoped>中的scoped 這個方法不建議使用,會改變佈局 二.定義兩個style標籤,一個含有scoped屬性,一個不含有scoped屬性 使用方法為 <

python pip install xxxx 中文路徑導致安裝庫時報錯問題解決方式

報錯內容:UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xd3 in position 7: ordinal not in range(128) 解決方案: 1.第一種辦法 在pycharm中開啟檔案(pyt

LeetCode——解決刪除陣列中重複元素問題方式

情景要求: (1)輸入的陣列元素為基本型別int。 (2)返回不含重複元素的陣列,其型別為基本型別int。 (3)對最後的結果陣列元素順序沒有要求,可亂序也可排序。 經過一系列的思考與實踐,總結出了以下三種不同情形“刪除陣列重複元素”的解決辦法。

用於解決多執行緒安全問題的方式

用於解決多執行緒安全問題的方式: 1. 同步程式碼塊 (隱式鎖) 2. 同步方法(隱式鎖) 3. 同步鎖 Lock( jdk 1.5 後)  注意:是一個顯示鎖,需要通過 lock() 方法上鎖,必須通過 unlock() 方法進行釋放鎖 下面舉一個售票例子: 1)同步程

session設定存活時間的方式

在web容器中設定(此處以tomcat為例) 在tomcat-5.0.28\conf\web.xml中設定,以下是tomcat 5.0中的預設配置: [html] view plain copy <!-- ====================

實踐解決跨域問題的方式剖析

最近在做我星際schub網站的時候,遇到了跨域問題,我先把後端node部署在了伺服器上,然後在本地localhost測試,出現了問題: 瀏覽器都提示我們使用這個header頭: 解決辦法: 1. CORS 伺服器設定響應頭: response.setHeader("Access-Control-Allow-

實現Session 過濾的方式

第一種方式:使用HttpModule實現過濾Session功能 新建一個HttpModuleHelper 工具類, 繼承 IHttpModule介面 程式碼如下 public class HttpModuleHelper : IHttpModule

在Mybatis中,解決資料庫欄位名與java實體類屬性名不一致的方式

在使用Mybatis來持久化資料庫時,有時候會碰到資料庫中表中的欄位與java實體類中屬性名不一致的情況,在這種情況下Mybatis是不能完成欄位的自動對映的。而通常情況下,資料庫及實體類是不應該被改的的。所以要在不改變資料庫以及實體類的情況下解決這個問題,下面是解決該問題

MySQL root使用者忘記密碼解決方案(安全模式,修改密碼的方式)

1.關閉正在執行的MySQL 2.啟動MySQL的安全模式,命令如下: mysqld --skip-grant-tables or mysqld-nd --skip-grant-tables 3.使用root使用者[免密碼]登陸MySQLmysql -u root -p輸

Struts2獲取Session方式

1、Map<String,Object> map =  ActionContext.getContext().getSession();2、HttpSession session = ServletActionContext.getRequest().getSes

解決dubbo註冊zookepper服務IP亂入問題的方式

最近做一個專案引入了dubbo+zookepper的分散式服務治理框架。在應用的釋出的時候出現一個怪問題。zookepper服務是起在開發伺服器192.168.23.180上。本機起應用服務提供者註冊到192.168.23.180上的dubbo服務可以註冊成功,用dubbo

Spring 依賴注入方式的實現,及迴圈依賴問題的解決(原始碼+XML配置)

搬磚啦,搬磚啦,這幾天在看Spring相關的書,下面給大家分享一下這幾天的心得與收穫,Go Go Go! Spring支援兩種依賴注入方式,分別是屬性注入,建構函式注入。除此之外,Spring還支援工廠注入方式。 接下來,我們一起來了解一下Spring的幾種注入方式。

Java設定session超時(失效)的方式

1.      在web容器中設定(此處以tomcat為例) 在tomcat-5.0.28\conf\web.xml中設定,以下是tomcat 5.0中的預設配置: <!-- ==================== Default Session Configur

解決電腦80埠被佔用的方式

一、IIS的服務引起的 1.關閉IIS的服務 2.關閉World Wide Web Publishing Service 二、這種情況比較變態,關閉了兩個都無效,也不是由tomcat佔用的,下面我們來看! 是IIS都已經停止了,實在沒辦法,就把IIS給刪除了,然後重

Java專案設定session超時(失效)的方式

1.      在web容器中設定(此處以tomcat為例) 在tomcat-5.0.28\conf\web.xml中設定,以下是tomcat 5.0中的預設配置: <!-- ==================== Default Session Co