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

京東雲開發者 發表於 2022-11-22
SQL

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的下午呀。


作者:馬躍