二、核心對象的生命周期
從上一篇文章中,我們可以看出mybatis操作數據庫主要使用了4個核心對象:SqlSessionFactoryBuilder,SqlSessionFactory, SqlSession和Mapper。那么,在軟件系統中,這個幾個對象的生命周期是什么樣的呢?什么時候創建?什么時候銷毀?
1. SqlSessionFactoryBuilder
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactoryBuilder 是用來創建SqlSessionFactory的,可以被實例化、使用和丟棄,一旦創建了SqlSesionFactory,就不再需要它了。因此,SqlSessionFactoryBuilder實例的最佳作用域是方法作用域,也就是局部方法變量。
2. SqlSessionFactory
SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在,沒有任何理由丟棄它或重新創建另一個實例。 使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重復創建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是應用作用域。 有很多方法可以做到,最簡單的就是使用單例模式或者靜態單例模式。
3. SqlSession
每個線程都應該有它自己的 SqlSession 實例。SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是請求或方法作用域。 絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。 也絕不能將 SqlSession 實例的引用放在任何類型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你現在正在使用一種 Web 框架,要考慮 SqlSession 放在一個和 HTTP 請求對象相似的作用域中。 換句話說,每次收到的 HTTP 請求,就可以打開一個 SqlSession,返回一個響應,就關閉它。 這個關閉操作是很重要的,你應該把這個關閉操作放到 finally 塊中以確保每次都能執行關閉。
4. Mapper
映射器是一些由你創建的、綁定你映射的語句的接口。映射器接口的實例是從 SqlSession 中獲得的。因此從技術層面講,任何映射器實例的最大作用域是和請求它們的 SqlSession 相同的。盡管如此,映射器實例的最佳作用域是方法作用域。 也就是說,映射器實例應該在調用它們的方法中被請求,用過之后即可丟棄。 並不需要顯式地關閉映射器實例,盡管在整個請求作用域保持映射器實例也不會有什么問題,但是你很快會發現,像 SqlSession 一樣,在這個作用域上管理太多的資源的話會難於控制。 為了避免這種復雜性,最好把映射器放在方法作用域內。
5. 總結
對象 | 生命周期 |
---|---|
SqlSessionFactoryBuilder | 方法作用域,創建完SqlSessionFactory后就銷毀 |
SqlSessionFactory | 應用作用域,貫穿整個應用,直到應用結束 |
SqlSession | 請求/方法作用域 |
Mapper | 方法作用域 |