1. 程式人生 > >關於在SpringMVC框架中 實現資料庫session會話環境變數的功能

關於在SpringMVC框架中 實現資料庫session會話環境變數的功能

前言:
由於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());
            }
        }
    }    

完工!