Mybatis 经常使用的几个对象

一、SqlSessionFactoryBuilder

这个类能够被实例化、使用和丢弃,一旦建立了 SqlSessionFactory,就再也不须要它了。所以 SqlSessionFactoryBuilder 实例的最佳范围是方法范围(也就是局部方法变量)。你能够重用 SqlSessionFactoryBuilder 来建立多个 SqlSessionFactory 实例,可是最好仍是不要让其一直存在以保证全部的 XML 解析资源开放给更重要的事情。那么SqlSessionFactoryBuilder一旦使用它建立完了SqlSessionFactory 就能够销毁了,这样也能够保证整个应用只有一个SqlSessionFactory java

二、SqlSessionFactory

每一个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例能够经过 SqlSessionFactoryBuilder 得到。而 SqlSessionFactoryBuilder 则能够从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。spring

能够从 XML 文件中构建 SqlSessionFactory ,也能够从 Java 程序而不是 XML 文件中建立。sql

SqlSessionFactory 一旦被建立就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复建立屡次,屡次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。所以 SqlSessionFactory 的最佳范围是应用范围。有不少方法能够作到,最简单的就是使用单例模式或者静态单例模式。数据库


三、SqlSession

每一个线程都应该有它本身的 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管理。

四、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
    }

}
相关文章
相关标签/搜索