如何構建mybatis線程安全的sqlsession對象

現象1:如果使用原生mybatis進行數據操作,那麼必須按照以下方式使用:

也就是要像原始的java.sql.Connection對象一樣,必須按照:新建連接->執行SQL->提交(查詢不需要)->如果操作數據存在異常需要回滾->釋放數據庫連接。
注意第一點和最後一點,每個SqlSession新建之後必須釋放,不然會造成數據庫連接泄露的危險。也就是意味着SqlSession是個有狀態的對象,是無法進行復用的,所以只能侷限於request或者方法的範圍,也就是所謂的線程不安全。

現象2:如果使用spring集成mybatis,官方提供了整和包mybatis-spring.jar,如果完成配置之後,使用方式及其簡單,簡單示例如下:

這裏的SqlSessionTemplate不僅是單例的,而且不需要手工新建和關閉SqlSession

問題1:

那麼問題來了,爲什麼mybatis-spring.jar中的SqlSessionTemplate可以被多個dao複用,而且不會造成數據連接泄露呢,並且還可以自動新建和釋放數據庫連接?
官方解答是因爲SqlSessionTemplate是線程安全的,也就是確保每個線程使用的sqlSession的唯一併不互相沖突。

首先看了一下mybatis-spring的源碼,發現SqlSessionTemplate是通過代理攔截和SqlSessionHolder實現的sqlsession線程安全和自動新建和釋放連接的。
看構造函數函數中構建代理類,該代理類實現SqlSession接口,定義了方法攔截器,如果調用代理類實例中實現SqlSession接口定義的方法,該調用則被導向SqlSessionInterceptor的invoke方法,這個方法中自動進行了SqlSession的自動請求和釋放(如果不被spring託管則自己新建和釋放sqlsession,如果被spring管理則使用SqlSessionHolder進行request和relase操作)

以下網址針對SqlSessionTemplate的線程安全特性進行了詳細的探究:http://www.cnblogs.com/daxin/p/3544188.html

問題2:

然後又想到這樣一個問題,雖然現在幾乎所有項目都使用spring作爲java程序的基本框架,如果我不使用spring管理mybatis,僅僅使用原始的mybatis,怎麼樣才能構建一個和SqlSessionTemplate相似的對象呢?

首先想到必須使用java的treadLocal構建一個sqlsession的對象,如ThreadLocal sqlSession = new ThreadLocal()。
經過查找,發現mybatis自身就有這樣一個類實現了類似的功能,類路徑:org.apache.ibatis.session.SqlSessionManager,但是沒有註釋,可能存在mybatis-spring這種神器之後,mybatis放棄了對這個類的維護。
該類實現了SqlSessionFactory, SqlSession並且在其中定義了一個treadLocal的sqlssion對象,同時使用了代理攔截進行了sqlsession的自動管理,具體代碼可以自己查閱,對於理解mybatis原理和java的代理機制很有幫助。

那麼寫個簡單的程序驗證一下SqlSessionManager是否真的可以保證線程安全和自動新建和釋放sqlssion:
TestSqlManager.java

我本機裝的mysql,通過監控語句:select SUBSTRING_INDEX(host,’:’,1) as ip , count(*) from information_schema.processlist group by ip;
發現執行過程中存在連接併發的情況,但是執行之後全部釋放掉了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章