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

HttpSession 線程安全風險與最佳實踐指南

     編輯:Java 相關知識

問題場景:購物車資料競態

典型電商場景:使用者從商品列表挑選 3 件商品並點擊「查看購物車」,同時在另一分頁繼續挑選。此時顯示購物車的頁面執行到一半,另一分頁的操作已修改 Session 中的商品列表,導致顯示的商品數量不再是 3 件。代碼片段:

HttpSession session = request.getSession();
List<Product> list = session.getAttribute("productCart");
myService.save(list); // 保存購物車數據到資料庫

HttpSession 為同一用戶多請求共享,屬線程不安全物件。多線程並發讀寫同一 Session 屬性時,極易產生資料不一致。

表象與本質:事務邊界的關鍵

雖然 Session 共享導致「表象上」的資料變動,但若正確使用資料庫事務保證資料準確性,表象問題可暫時忽略。真正的風險在於業務層處理過程中 Session 物件被外部修改,導致業務邏輯操作的資料與提交時的資料不一致。

錯誤示範:直接傳遞 Session 物件

場景:Session 中有 3 件商品,業務層循環計算總價,計算完成準備保存時,Session 被修改為 4 件。結果:保存 4 件商品,但總價仍按 3 件計算 → 資料不一致。

正確做法:深拷貝隔離業務資料

在 Controller 層將 Session 資料深拷貝至新集合,傳遞給 Service 層:

HttpSession session = request.getSession();
List<Product> list = session.getAttribute("productCart");
List<Product> listNew = new ArrayList<>();
for (Product p : list) {
    Product pNew = new Product();
    pNew.setProductId(p.getProductId());
    // 複製其他屬性...
    listNew.add(pNew);
}
myService.save(listNew); // 安全:業務層操作獨立副本

此時即使 Session 變更,listNew 不受影響,保存的商品數量與價格一致。

核心原則總結

  1. Java 物件傳遞的是引用:多處持有同一引用,任一處修改皆影響其他處。
  2. 邊界隔離:Web 層(Controller)負責從 Session 取資料並深拷貝,傳遞給 Service 層的純資料物件(DTO/VO)。
  3. 隱蔽 Bug 警示:線程安全問題往往隱蔽,出錯時難定位。養成「取用即拷貝」習慣,從源頭消除共享可變狀態。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved