讓不同的Servlet在一個Session共享連接_JSP教程

      編輯Tag賺U幣
      教程Tag:暫無Tag,歡迎添加,賺取U幣!

      推薦:講解Linux系統下JDK、Tomcat的安裝
      本文詳細講解Linux系統下JDK、Tomcat的安裝 Jdk安裝: [root@b home]# ls jdk-1_5_0_12-linux-i586-rpm.bin lost found oracle 1、將jdk進行解壓 [root@b home]# ./jdk-1_5_0

      ==== 問題所在 ====

      如果要編寫一個購物車,通常需要寫很多個不同功能的servlet。例如用戶登錄、添加商品、查詢購物車、結帳等。

      在這些 servlet 中都需要讀寫數據庫。如果我們在每個 servlet 中都進行連接 -> 讀寫 -> 斷開連接的操作,就會消耗大量的服務器資源,不僅程序響應速度減緩,而且會加重服務器和數據庫的負擔。

      ==== 把希望寄托于 HttpSession ====

      如我們所學,Servlet API 提供了一些方法和類來專門處理短期的會話跟蹤。網站的每個用戶都和 javax.servlet.http.HttpSession 對象有關,servlet使用這個對象來記錄和檢索每個用戶的信息。

      幸運的是,我們可以在會話對象中存儲任意的 java 對象。存儲的方法大家都已經很熟悉,就是使用 setAttribute()方法。代表數據庫連接的Connection也不例外。

      這就為我們讓不同的servlet在一個session內共享鏈接帶來的希望。

      ==== 安全問題 ====

      那么,僅僅像下面這樣做就可以了么?

      1、在Servlet1中,向session中設置一個屬性:

      session.setAttribute("connection", connection);

      2、在Servlet2中,取出這個屬性:

      Connection connection = (Connection) session.getAttribute ("connection");

      理論上,沒有問題。在 Servlet1 中產生的 Connection 對象,到了 Servlet2 中可以繼續使用。

      但是如果 Servlet2 不小心改變了 connection 的引用,例如 connection = null; 那么,當它再次把這個connection放入session的屬性當中,其它的 servlet 就會得到一個指向 null 的 connection!

      ==== 解決之道 ====

      把 connection 直接在 session 中傳來傳去,看來不怎么安全。

      解決思路是,我們找一個專門的人來保管這個 connection,在得到請求的時候,由這個人把 connection 的引用返回給調用者。這樣,即使調用者不小心把它得到的那份 connection 搞壞了,保管著手里也總還有一個備份。

      相應的,在 session 的屬性中,我們不再保存 connection 本身,而是把這個保管者存進去。因為他能隨時給我們一個可用的 connection。

      這個類的具體寫法是:

      public class ConnectionHolder {
      public ConnectionHolder(Connection con) {
      // 保存連接
      this.con = con;
      try {
      // 禁用自動提交,以隔離不同session之間的操作。
      con.setAutoCommit(false);
      }
      catch(SQLException e) {
      // 錯誤處理代碼
      }
      }
      public Connection getConnection() {
      // 通過這個getter方法獲取連接
      return con;
      }
      private Connection con = null; // 設置為私有變量,這很重要,以確保變量安全。
      }
      ==== 使用方法 ====

      每個 servlet 在希望取得數據庫連接的時候,先看看 session 中是否有這個“保管者”(即上面的ConnectionHolder)。

      如果有的話,直接調用它的get方法,取得數據庫連接。

      如果沒有的話,說明這個session還沒有連接過數據庫,那么當前類就立刻創建一個數據庫連接,并把這個連接交給保管者,然后再把保管者放入 session 中,以便后續的 servlet 使用。

      下面是一個實例:

      1 protected void doGet(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
      2
      3 // 同步代碼取得數據庫連接
      4 synchronized (session) {
      5 // 看看這個持有者是否已經在 session 中了
      6 ConnectionHolder holder = (ConnectionHolder) session.getAttribute
      ("servletapp.connection");
      7
      8 // 如果不在,就創建一個數據庫連接,并把它交給持有者。
      9 if (holder == null) {
      10 try {
      11 holder = new ConnectionHolder(DriverManager.getConnection(
      "Connection URL"));
      12 session.setAttribute("servletapp.connection", holder);
      13 }
      14 catch (SQLException sqle) {
      15 // 錯誤處理代碼
      16 }
      17 }
      18
      19 // 從容器取得實際連接
      20 conn = holder.getConnection();
      21 }
      .... // 別忘了commit
      }
      這段代碼看起來有那么幾行。但實際上,在每個session中,只有第一次執行的servlet需要進行數據庫連接操作,此后的servlet只會執行第4、6、20這三行。

      ==== 誰來負責斷開連接? ====

      當 servlet 們不必再為創建數據庫連接費心的時候,也就沒有人愿意管關閉連接這檔子事了。事實上,更重要的是,他們沒法管。因為這個連接是放在 session 中的,而沒有誰能準確的預測,一個 session 會何時終止。

      好在有一種叫做“監聽器”(Listener)的東西可以專門管這件事。Listener有很多方法,其中的兩個方法是:

      public void valueBound(HttpSessionBingEvent event);

      public void valueUnbound(HttpSessionBingEvent event);

      這兩個方法可以在一個 session 被創建/失效的時候分別自動執行。我們就把關閉連接的代碼放在第二個方法中,這樣,當一個 session 失效的時候,數據庫連接就會自動關閉。

      要想讓一個類成為Listener,只需讓它實現 HttpSessionBindingListener 接口。我們的 connection 是由 ConnectionHolder 這個類來保管的,因此最方便的辦法就是把它注冊成一個監聽器。

      具體方法是:

      public void valueUnbound(HttpSessionBindingEvent event) {
      // 當從Session刪除或當Session結束時,關閉數據連接。
      try {
      if (con != null) {
      con.rollback(); // 放棄所有未提交的數據
      con.close();
      }
      }
      catch (SQLException e) {
      // 錯誤處理代碼
      }
      }
      ==== 完整示例 ====

      下面是一個完整的 ConnectionHolder:

      import javax.servlet.http.HttpSessionBindingListener;
      import javax.servlet.http.HttpSessionBindingEvent;
      import java.sql.Connection;
      import java.sql.SQLException;
      public class ConnectionHolder implements HttpSessionBindingListener {
      public ConnectionHolder(Connection con) {
      // 保存連接
      this.con = con;
      try {
      con.setAutoCommit(false);
      }
      catch(SQLException e) {
      // 錯誤處理代碼
      }
      }
      public Connection getConnection() {
      return con;
      }
      public void valueBound(HttpSessionBindingEvent event) {
      // 當增加Session時,什么也不做
      }
      public void valueUnbound(HttpSessionBindingEvent event) {
      // 當從Session刪除或當Session結束時,關閉數據連接。
      try {
      if (con != null) {
      con.rollback(); // 放棄所有未發送數據
      con.close();
      }
      }
      catch (SQLException e) {
      // 錯誤處理代碼
      }
      }
      private Connection con = null;
      }

      分享:Linux系統下兩種自動啟動Tomcat的方法
       有很多辦法可以讓Tomcat在系統啟動的時候自動運行,我這里介紹兩種方法,一種簡單,另外一種復雜而專業。在介紹這兩個方法前你應該先裝JDK,Tomcat。Tomcat的安裝很簡單,下載二進制壓縮包

      來源:模板無憂//所屬分類:JSP教程/更新時間:2008-08-22
      相關JSP教程