這個類能夠被實例化、使用和丟棄,一旦建立了 SqlSessionFactory,就再也不須要它了。所以 SqlSessionFactoryBuilder 實例的最佳範圍是方法範圍(也就是局部方法變量)。你能夠重用 SqlSessionFactoryBuilder 來建立多個 SqlSessionFactory 實例,可是最好仍是不要讓其一直存在以保證全部的 XML 解析資源開放給更重要的事情。那麼SqlSessionFactoryBuilder一旦使用它建立完了SqlSessionFactory 就能夠銷燬了,這樣也能夠保證整個應用只有一個SqlSessionFactory java
每一個基於 MyBatis 的應用都是以一個 SqlSessionFactory 的實例爲中心的。SqlSessionFactory 的實例能夠經過 SqlSessionFactoryBuilder 得到。而 SqlSessionFactoryBuilder 則能夠從 XML 配置文件或一個預先定製的 Configuration 的實例構建出 SqlSessionFactory 的實例。spring
能夠從 XML 文件中構建 SqlSessionFactory ,也能夠從 Java 程序而不是 XML 文件中建立。sql
SqlSessionFactory 一旦被建立就應該在應用的運行期間一直存在,沒有任何理由對它進行清除或重建。使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重複建立屢次,屢次重建 SqlSessionFactory 被視爲一種代碼「壞味道(bad smell)」。所以 SqlSessionFactory 的最佳範圍是應用範圍。有不少方法能夠作到,最簡單的就是使用單例模式或者靜態單例模式。數據庫
每一個線程都應該有它本身的 SqlSession 實例。SqlSession 的實例不是線程安全的,所以是不能被共享的,因此它的最佳的範圍是請求或方法範圍。絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。也毫不能將 SqlSession 實例的引用放在任何類型的管理範圍中,好比 Serlvet 架構中的 HttpSession。若是你如今正在使用一種 Web 框架,要考慮 SqlSession 放在一個和 HTTP HttpRequest請求對象類似的範圍中。換句話說,每次收到的 HTTP 請求,就能夠打開一個 SqlSession,返回一個響應,就關閉它。這個關閉操做是很重要的,你應該把這個關閉操做放到 finally 塊中以確保每次都能執行關閉。下面的示例就是一個確保 SqlSession 關閉的標準模式:緩存
SqlSession session = sqlSessionFactory.openSession();安全
try {session
// do workmybatis
} finally {架構
session.close();app
}
在你的全部的代碼中一致性地使用這種模式來保證全部數據庫資源都能被正確地關閉。
Spring 依賴注入框架能夠建立線程安全的、基於事務的 SqlSession 和映射器(mapper)並將它們直接注入到你的 bean 中,所以它們的生命週期將交給Spring管理。
他是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 } }