Mybatis 常用的幾個對象

wulunyong 8年前發布 | 39K 次閱讀 MyBatis3 持久層框架

來自: http://my.oschina.net/heweipo/blog/616318


1、SqlSessionFactoryBuilder

這個類可以被實例化、使用和丟棄,一旦創建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 實例的最佳范圍是方法范圍(也就是局部方法變量)。你可以重用 SqlSessionFactoryBuilder 來創建多個 SqlSessionFactory 實例,但是最好還是不要讓其一直存在以保證所有的 XML 解析資源開放給更重要的事情。那么SqlSessionFactoryBuilder一旦使用它創建完了SqlSessionFactory 就可以銷毀了,這樣也可以保證整個應用只有一個SqlSessionFactory 

2、SqlSessionFactory

每個基于 MyBatis 的應用都是以一個 SqlSessionFactory 的實例為中心的。SqlSessionFactory 的實例可以通過 SqlSessionFactoryBuilder 獲得。而 SqlSessionFactoryBuilder 則可以從 XML 配置文件或一個預先定制的 Configuration 的實例構建出 SqlSessionFactory 的實例。

可以從 XML 文件中構建 SqlSessionFactory ,也可以從 Java 程序而不是 XML 文件中創建。

SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在,沒有任何理由對它進行清除或重建。使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重復創建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞味道(bad smell)”。因此 SqlSessionFactory 的最佳范圍是應用范圍。有很多方法可以做到,最簡單的就是使用單例模式或者靜態單例模式。

 

3、SqlSession

每個線程都應該有它自己的 SqlSession 實例。SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的范圍是請求或方法范圍。絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。也絕不能將 SqlSession 實例的引用放在任何類型的管理范圍中,比如 Serlvet 架構中的 HttpSession。如果你現在正在使用一種 Web 框架,要考慮 SqlSession 放在一個和 HTTP HttpRequest請求對象相似的范圍中。換句話說,每次收到的 HTTP 請求,就可以打開一個 SqlSession,返回一個響應,就關閉它。這個關閉操作是很重要的,你應該把這個關閉操作放到 finally 塊中以確保每次都能執行關閉。下面的示例就是一個確保 SqlSession 關閉的標準模式:

SqlSession session = sqlSessionFactory.openSession();

try {

  // do work

} finally {

  session.close();

}

在你的所有的代碼中一致性地使用這種模式來保證所有數據庫資源都能被正確地關閉。

Spring 依賴注入框架可以創建線程安全的、基于事務的 SqlSession 和映射器(mapper)并將它們直接注入到你的 bean 中,因此它們的生命周期將交給Spring管理。

4、SqlSessionTemplate

他是org.mybatis.spring包下面的類,而且他還實現sqlSession,但是他sqlSession的操作都是由他內部的成員sqlSessionProxy處理完成的,這個對象的實例其實是DefaultSqlSession。無論如何,他是Spring相關的,他的生命周期應該由Spring的來管理,那么涉及到 sqlSession的管理,事務的隔離,甚至緩存的控制。這些內部都已經處理完成,我們使用時只需要直接調用 SqlSessionTemplate 的數據操作方法,對于session的關閉,我們不需要擔心,另外,雖然 SqlSessionTemplate 是在Spring采用構造方法的方式注入,默認就是一個單例,但是我們在應用當中,實際每次一個事務我們都會實例化一個DefaultSqlSession,而且處理完之后也會關閉,如果一個事務中有多個數據操作,那么他們使用的是同一個sqlsession。對于一個擁有事務的sqlsession,他的關閉時期是在事務提交的時候關閉,換句話說,關閉sqlsession是事務應該負責的,但是如果沒有被事務管理,你們自己進行關閉。

每次執行數據操作時獲取sqlsession的代碼:

SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
SqlSession session = sessionHolder(executorType, holder);
if(session != null) {
    return session; // 如果已經存在,那么直接返回
} else {
    if(LOGGER.isDebugEnabled()) {
        LOGGER.debug("Creating a new SqlSession");
    }
    session = sessionFactory.openSession(executorType); // 如果不存在,應該生成,而且存放在SessionHolder中管理
    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
    return session;
}

 

代理執行數據操作的代碼

SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator); // 獲取DefaultSqlSession
Object unwrapped;// 返回值,會默認被緩存在內存中(一級緩存)
try {
    Object t = method.invoke(sqlSession, args); // 代理調用數據操作方法
    if(!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
        sqlSession.commit(true); // 判斷這個sqlsession是否是被事務容器所管理,沒有被管理則自己提交,被管理則事務提交
    }
    unwrapped = t;
} catch (Throwable var11) {
    unwrapped = ExceptionUtil.unwrapThrowable(var11);
    if(SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
        SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);// 關閉sqlsession
        sqlSession = null;
        DataAccessException translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
        if(translated != null) {
            unwrapped = translated;
        }
    }
    throw (Throwable)unwrapped;
} finally {
    if(sqlSession != null) {
        SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); // 關閉sqlsession
    }

}

 


 

 本文由用戶 wulunyong 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!