HttpSession session = request.getSession();
List<Product> list = session.getAttribute("productCart");
myService.save(list); // 保存購物車數據到數據庫
這個對象會被多次使用,也會被同一個用戶的多個頁面使用,所以他對於系統來說是線程不安全的。
比如用戶在從產品列表裡面選擇產品,這面選擇3種,他點了查看購物車
該用戶還開了另一個頁面,繼續選擇產品。
此時,在顯示購物車的頁面,有可能運行在一半時,其已經選擇的產品列表,並另一個頁面的操作修改了。所以顯示的產品數量有可能並不是3種。
因為session需要維持當前用戶的信息,所以其在多個線程裡是共享的。所以是線程不安全的。
不過,這個是表面現象,我們只要正確使用事務,保證數據的准確性,表面的問題可以不用管它。
我們可以把session裡面的數據另外保存到一個新的數據對象裡,這個對象不再因為session的改變而出現變動。這個對象傳遞給業務層進行事務處理,保證數據級別的准確。
千萬不要把session,或者 session裡面的對象直接傳遞給業務層,因為你的業務處理一半時,同樣可能出現session對象被改變的情況。有可能造成重要數據出現偏差。
舉例:
session 對應三個產品,
事務裡面循環了產品,並計算了總價格,
計算完畢,准備保存時,session變了,產品變成了4個。
此時開始保存。產品保存了4個,可總價格卻還是3個的。
出現了數據不一致。
修改後的例子
session 對應三個產品
重新生成一個產品對象數組,把session數據復制過來,然後傳遞給業務層
事務裡面循環計算總價格
計算完畢,此時session變了,但並不影響我們這個新的產品數組對象
保存,三個產品,價格也正確。
HttpSession session = request.getSession();
List<Product> list = session.getAttribute("productCart");
List<Product> listNew = new ArrayList<Product>();
Product pNew;
for(Product p : list){
pNew = new Product();
pNew.setProductId(p.getProductId());
// 其它的復制參數的語句
listNew.add(pNew); // 保存到新的列表裡面
}
myService.save(listNew); // 保存購物車數據到數據庫,這個是安全的
總結:
有些線程安全問題是很隱蔽的,等你出了問題,很可能根本不認為會是那裡出的問題。記住一點,Java裡面的對象傳遞的是對象的引用,只要2個地方用了相同的引用,則其它地方的變動,這一面也會變動。
原文:http://www.java2000.net/p9667