天天看點

一個甯靜祥和沒有bug的下午和SqlSession的故事

作者:京東雲

1 背景

這是一個安靜祥和沒有bug的下午。

作為一隻菜雞,時刻鞏固一下基礎還是很有必要的,如此的大好時機,就讓我來學習學習mybatis如何使用。

一個甯靜祥和沒有bug的下午和SqlSession的故事

這可和我看到的不一樣啊,讓我來看看項目裡怎麼寫的。

一個甯靜祥和沒有bug的下午和SqlSession的故事

我們項目中的Dao都繼承于BaseDao,而BaseDao繼承于SqlSessionDaoSupport,每次執行sql的時候都是直接将這個sqlSession傳回,然後執行sql,這難道不是一個執行個體變量嘛?這和你說的可不一樣诶。于是帶着這樣的疑問,我開始了探索。

2 探索之旅

1)我們都知道,在使用mybatis時,sqlSession都來自于sqlSessionFactory,而sqlSessionFactory可以通過sqlSessionFactoryBuilder建立,也可以通過spring初始化,而項目中很顯然采取了後一種方式。

一個甯靜祥和沒有bug的下午和SqlSession的故事

2)那麼我們已經得到了sqlSessionFactory,應該如何去進一步探索sqlSession的來源呢,我想到可以通過項目中已經實作的dao進行探索。我們随便選取一個dao為例。

一個甯靜祥和沒有bug的下午和SqlSession的故事

它繼承了BaseDao。

一個甯靜祥和沒有bug的下午和SqlSession的故事

而BaseDao又繼承了SqlSessionDaoSupport,在BaseDao中調用了getSqlSession方法,實際上也就是SqlSessionDaoSupport的getSqlSession方法。

一個甯靜祥和沒有bug的下午和SqlSession的故事

而SqlSessionDaoSupport的getSqlSession方法是直接将自己的成員變量傳回去的,截至目前為止,和我的懷疑點是相符合的,即目前的寫法和mybatis官網的說明是沖突的。

3)反複閱讀SqlSessionDaoSupport這個類後,終于被我發現了線索,細心的小夥伴應該也早已發現了,就在上圖之中的注釋中,“使用者應該使用這個方法來獲得一個SqlSession來執行sql語句,這個SqlSession被spring管理,使用者不應該送出、復原或關閉它。因為這些已經被自動執行了。”

同時,這個方法會傳回一個線程安全的SqlSession。

一個甯靜祥和沒有bug的下午和SqlSession的故事

那麼這個SqlSession是從何而來的呢,從上圖可以看出,它有兩種指派方式,一種是給他傳一個SqlSessionFactory,生成SqlSessionTemplate,SqlSessionTemplate即為sqlSession。另一種是直接給他傳一個SqlSessionTemplate作為SqlSession。根據本類的注釋,如果SqlSessionFactory和SqlSessionTemplate都被定義了,那麼SqlSessionFactory的方式會失效。至此,我的上述疑問已經解決了,也就是說這個SqlSession并不是一個mybatis初始的SqlSession,而是spring實作的SqlSessionTemplate。

4)但是,我又誕生了新的疑問,SqlSessionTemplate是怎麼完成線程安全的呢?

一個甯靜祥和沒有bug的下午和SqlSession的故事

于是我進入了SqlSessionTemplate的方法執行,發現實際執行語句的都是這個代理類sqlSessionProxy。

一個甯靜祥和沒有bug的下午和SqlSession的故事

而代理工作内容就在SqlSessionInterceptor這個handler裡。

一個甯靜祥和沒有bug的下午和SqlSession的故事

進入其中,我們終于發現了它的擷取和關閉操作。

一個甯靜祥和沒有bug的下午和SqlSession的故事
一個甯靜祥和沒有bug的下午和SqlSession的故事

也就是說,每次執行,代理都會調用sessionFactory的openSession方法獲得一個新的session。

3 總結

終于的終于,mybatis,spring,項目以及我的疑問得到了統一,真是一個甯靜祥和而又沒有bug的下午呀。

作者:馬躍

繼續閱讀