首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

讓多個 Servlet 在同一 Session 中安全共享數據庫連接

     編輯:Java 相關知識

購物車等場景涉及多 Servlet 協作,若各自開關連接將耗盡資源。HttpSession 可存放任意對象,但直接存 Connection 存在引用竄改風險。本文提出「連接持有者」模式 + HttpSessionBindingListener 自動清理,實現安全共享。

一、問題與風險

// Servlet1
session.setAttribute("connection", conn);

// Servlet2  -- 危險!
Connection c = (Connection) session.getAttribute("connection");
c = null;  // 竄改引用
session.setAttribute("connection", c);  // 污染共享對象

二、解決方案:ConnectionHolder 封裝 + 私有字段

public class ConnectionHolder implements HttpSessionBindingListener {
    private Connection con;  // 私有,防外部竄改

    public ConnectionHolder(Connection con) {
        this.con = con;
        try { con.setAutoCommit(false); }  // 隔離事務
        catch (SQLException e) { /* handle */ }
    }

    public Connection getConnection() { return con; }

    // Session 綁定/解綁回調
    public void valueBound(HttpSessionBindingEvent e) { /* no-op */ }
    public void valueUnbound(HttpSessionBindingEvent e) {
        try {
            if (con != null) { con.rollback(); con.close(); }
        } catch (SQLException ex) { /* handle */ }
    }
}

三、Servlet 統一獲取邏輯

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
    HttpSession session = req.getSession();
    Connection conn;
    synchronized (session) {  // 並發安全
        ConnectionHolder holder = (ConnectionHolder) session.getAttribute("servletapp.connection");
        if (holder == null) {
            holder = new ConnectionHolder(DriverManager.getConnection("jdbc:dm://..."));
            session.setAttribute("servletapp.connection", holder);
        }
        conn = holder.getConnection();
    }
    // 使用 conn 進行業務操作...
    // 記得手動 commit/rollback
}

四、關鍵設計點

機制作用
私有 con + 唯讀 getConnection()防止調用者竄改引用
setAutoCommit(false)隔離不同請求事務,統一由業務代碼控制提交
synchronized(session)雙重檢查鎖模式,避免並發重複創建
實現 HttpSessionBindingListenerSession 失效/超時自動觸發 valueUnbound 關閉連接,無需手動攔截

五、完整類代碼

import javax.servlet.http.*;
import java.sql.*;

public class ConnectionHolder implements HttpSessionBindingListener {
    private Connection con = null;

    public ConnectionHolder(Connection con) {
        this.con = con;
        try { con.setAutoCommit(false); } catch (SQLException e) { /* log */ }
    }
    public Connection getConnection() { return con; }
    public void valueBound(HttpSessionBindingEvent e) {}
    public void valueUnbound(HttpSessionBindingEvent e) {
        try { if (con != null) { con.rollback(); con.close(); } }
        catch (SQLException ex) { /* log */ }
    }
}

此模式適用於傳統 Servlet/JSP 架構;現代框架(Spring、JPA)建議使用成熟的連接池與聲明式事務管理,避免手動管理連接生命週期。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved