典型電商場景:使用者從商品列表挑選 3 件商品並點擊「查看購物車」,同時在另一分頁繼續挑選。此時顯示購物車的頁面執行到一半,另一分頁的操作已修改 Session 中的商品列表,導致顯示的商品數量不再是 3 件。代碼片段:
HttpSession session = request.getSession();
List<Product> list = session.getAttribute("productCart");
myService.save(list); // 保存購物車數據到資料庫
HttpSession 為同一用戶多請求共享,屬線程不安全物件。多線程並發讀寫同一 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 不受影響,保存的商品數量與價格一致。