您好,登錄后才能下訂單哦!
可以說每個MyBatis都是以一個SqlSessionFactory實例為中心的。SqlSessionFactory實例可以通過SqlSessionFactoryBuilder來構建。一是可以通過XML配置文件的方式來構建SqlSessionFactory,二是可以通過Java API的方式來構建。但不管通過什么方式都有一個Configuration貫穿始終,各種配置正是通過Configuration實例來完成實現。
此篇文章旨在通過編碼實現MyBatis3.4.1 User Guide所提到的作用域和生命周期指導建議。為什么要了解作用域和生命周期呢?在作用域內正確地使用SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession會讓我們避免多線程環境下并發所帶來的問題。當然如果使用依賴(DI)注入框架(Spring)可不用在代碼中關心作用域問題,因為依賴注入框架會為我們做好幾乎一切工作。
首先我們來看User Guide對SqlSessionFactoryBuilder作用域以及生命周期的指導意見。
SqlSessionFactoryBuilder
這個類可以被實例化、使用和丟棄,一旦創建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 實例的最佳范圍是方法范圍(也就是局部方法變量)。你可以重用 SqlSessionFactoryBuilder 來創建多個 SqlSessionFactory 實例,但是最好還是不要讓其一直存在以保證所有的 XML 解析資源開放給更重要的事情。
SqlSessionFactory
SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在,沒有任何理由對它進行清除或重建。使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重復創建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞味道(bad smell)”。因此 SqlSessionFactory 的最佳范圍是應用范圍。有很多方法可以做到,最簡單的就是使用單例模式或者靜態單例模式。
SqlSession
每個線程都應該有它自己的 SqlSession 實例。SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的范圍是請求或方法范圍。絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。也絕不能將 SqlSession 實例的引用放在任何類型的管理范圍中,比如 Serlvet 架構中的 HttpSession。如果你現在正在使用一種 Web 框架,要考慮 SqlSession 放在一個和 HTTP 請求對象相似的范圍中。換句話說,每次收到的 HTTP 請求,就可以打開一個 SqlSession,返回一個響應,就關閉它。這個關閉操作是很重要的,你應該把這個關閉操作放到 finally 塊中以確保每次都能執行關閉。
通過User Guide可以看到官方對SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession的作用域范圍分別是:方法范圍、應用范圍、請求或方法范圍。初學者很容易將SqlSessionFactory的作用域范圍忽略,而將其和SqlSessionFactoryBuilder和SqlSession都置于方法范圍內,這樣本身并不會帶來程序代碼錯誤(只有在將SqlSession置于應用范圍才會帶來并發性問題),然而這會被認為是“bad smell”。我在第一篇寫《MyBatis3入門》時,就沒有仔細閱讀User Guide以至于代碼聞起來有一種“壞味道(bad smell)”。例,代碼如下:
1 public class SessionFactory {2 public static SqlSession getSqlSession(String resource) throws IOException{3 InputStream inputStream = Resources.getResourceAsStream(resource);4 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);5 SqlSession sqlSession = sqlSessionFactory.openSession();6 7 return sqlSession;8 }9 }
第4行的代碼聞起來就有一個“bad smell”的味道,因為它的作用不是在整個應用范圍而是在方法范圍。
而什么是較好的代碼呢?我們應該如上所說,對SqlSessionFactory使用單例模式。重構后的代碼如下:
1 package day_8_mybatis.util; 2 3 import java.io.InputStream; 4 5 import org.apache.ibatis.session.SqlSessionFactory; 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 8 /** 9 * @author turbo10 *11 * 2016年10月26日12 */13 public class SessionFactory2 {14 private static SqlSessionFactory sqlSessionFactory;15 16 public static synchronized SqlSessionFactory getInstance(InputStream inputStream){17 if (null == sqlSessionFactory){18 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);19 }20 21 return sqlSessionFactory;22 }23 }
客戶端創建SqlSession的代碼如下:
1 package day_8_mybatis; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 6 import org.apache.ibatis.io.Resources; 7 import org.apache.ibatis.session.SqlSession; 8 9 import day_8_mybatis.util.SessionFactory2;10 11 /**12 * 客戶端13 * 14 * @author turbo15 *16 * 2016年10月26日17 */18 public class Main {19 20 /**21 * @param args22 * @throws IOException23 */24 public static void main(String[] args) throws Exception {25 String resource = "day_8_mybatis/mybatis-config.xml"; // 獲取mybatis配置文件路徑26 InputStream inputStream = Resources.getResourceAsStream(resource);27 SqlSession sqlSession = SessionFactory2.getInstance(inputStream).openSession();28 29 }30 31 }
這樣的代碼是不是就符合標準,并且看起來舒服多,漂亮多了?
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。