前言:
由於SpringMVC框架對於數據庫會話處理方面,實現了會話池的功能,以提高數據庫的工作效率。因爲在數據庫申請一個新的會話session確實是比較耗資源。
問題:
但是,這樣子,session被公用就帶來一個新的問題:數據庫的session級的環境變量就可能不可以直接使用了。
首先我們要理解,爲什麼要用數據庫的session的環境變量?用過OracleEBS開發的人都知道,數據庫的session環境變量是相互隔離的:不同的session,session級的環境變量不同。舉個例子,用戶A登錄用一個session,可以在session級添加一個環境變量:用戶是A。然後,這個會話的所有的DML修改,獲取新增人或者更新用戶的時候,都可以自動抓到該session的環境變量即可。
可以大大提高開發的工作效率。
但是,由於SpringMVC框架的原因,在jdbc調用數據庫的時候,可能session被公用。這樣子就很可能出現張冠李戴的問題了。
問題解決:
這個問題也困擾了一點時間。
最後我的解決辦法是:
在Service層添加一個AOP初始化對應的會話的環境變量。切面所有的Service的代碼,在代碼執行之前,先重新初始化該session的環境變量,即可。
需要注意的是,這樣子做必須要注意2個問題:
1 Service層必須是啓用Transaction事務處理的。因爲啓用了事務處理,service在調用數據庫session的時候,纔可以線程安全。經過測試,如果一個事務沒執行完畢;另外一個新的sql要做事務的時候,是自動調用一個新的數據庫session的!
2 需要注意SpringMVC框架的單例模式而帶來的安全性的問題。
最簡單初始化環境變量的ID是通過參數,從controller層傳到Service層。這樣子就沒風險了。然後AOP可以直接監控到對應的ID,再自動初始化環境變量。但是,這個辦法有一個致命的缺點:就是必須爲每個方法添加參數。對於大型系統來說簡直是噩夢,要改N個功能。
所以,我用的是另外一個辦法:用java.lang.ThreadLocal技術提供線程安全。然後,在AOP運行的時候,可以自動獲取到對應的初始化環境變量的ID信息,進行初始化。
具體步驟:
在Controller層,抓取session對應的環境變量ID,對service層進行初始化:
UVS.setLoginId((Long)sess.getAttribute("LOGIN_ID"));
對應的,在Service層添加ThreadLocal技術的成員變量:
private ThreadLocal<Long> loginIdTL = new ThreadLocal<Long>();
public Long getLoginId() {
return this.loginIdTL.get();
}
public void setLoginId(Long loginId) {
this.loginIdTL.set(loginId);
}
最後,寫一個AOP,切所有的service層的代碼,進行環境變量的自動初始化:
/***
* service層調用之前先自動初始化環境變量
* @throws Exception
*/
@Before("execution(* com.xinyiglass.springSample.service..*.*(..))")
public void alb2bInit(JoinPoint joinPoint) throws Exception{
Method method = null;
Object target = null;
Long loginId=null;
String methodName = "getLoginId";
target = joinPoint.getTarget();
method = getMethodByClassAndName(target.getClass(), methodName);
if(method!=null){
loginId=(Long) method.invoke(target);//LogUtil.log("loginId:"+loginId);
if(loginId!=null&&loginId>0&&loginId!=utilDao.getLoginId()){
PlsqlRetValue ret =utilDao.alb2bInit(loginId);//初始化環境變量!
if(ret!=null&&!TypeConvert.isNullValue(ret.getErrbuf())) LogUtil.log("ret:"+ret.toJsonStr());
}
}
}
完工!
後語:
必須要理解幾個知識點。
特別是關於Spring單例模式導致其層的全局變量的問題:
http://blog.sina.com.cn/s/blog_12bf601660102uwq2.html