Mybatis精讲二生命周期

39次阅读

共计 4201 个字符,预计需要花费 11 分钟才能阅读完成。

[TOC]

回顾

  • 上一章节我们通过 xml 和代码的方式实现了 Mybatis 环境的配置。代码方式只是简单介绍下。我们也知道我们大部分情况使用的是 xml 方式的配置。在实际开发中我们那样开发显然是不合理的。
  • 上章节提到的组件显示不可能每次执行 sql 都要重新创建的。这样性能上肯定是过不去的。今天我们就来简单聊聊 SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper 这些组件的生命周期吧。

SqlSessionFactoryBuilder

  • 通过观察分析这个类我们就知道既然是 Builder 模式的类,那他的作用就是构建起 (孵化器). 换句话说这个类不是那么的重要,因为他唯一的作用就是孵化 SqlSessionFactory。在 Spring 与 Mybatis 整合的框架中,我相信 Spring 一定是在构建了 SqlSessionFactory 之后就将这个类进行回收了。因为后面就不需要了。这里纯属个人猜想。

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
  try {XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    return build(parser.parse());
  } catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);
  } finally {ErrorContext.instance().reset();
    try {inputStream.close();
    } catch (IOException e) {// Intentionally ignore. Prefer previous error.}
  }
}
  • 上面就是我们通过加载 xml 配置文件的源码。我们不难发现 build 核心是通过 XMLConfigBuilder 这个类去负责解析 mybatis-config.xml 配置文件并生成 Configuration 对象。

SqlSessionFactory

  • 看名字就知道是工厂模式。在这里我们可以把他看成数据库连接池。既然是工厂就肯定得有产品。SqlSessionFactory 的产物就是 SqlSession。SqlSession 是与数据库的一次连接。管理数据库的连接的自然就是连接池了。
  • Mybatis 中使用的 SqlSessionFactory 是 DefaultSqlSessionFactory。以连接池的角度看待我们不难推断出 SqlSessionFactory 应该是个单例。SqlSessionFactory 对应的是数据库。一个数据库原则上应该对应一个 SqlSessionFactory 来管理。这点在 Spring 中正好无缝连接。把 SqlSessionFactory 交由 spring 管理。spring 默认是单例模式 bean.

openSessionFromDataSource

  • SqlSessionFactory 通过 openSession 方法获取 SqlSession.SQLSession 实际上可以看做是一次数据库的连接。下面我们通过源码的方式去看看工厂是如何生产 SqlSession 的。
<!-- 定义数据库信息,默认使用 development 数据库构建环境 -->
<environments default="development">
    <environment id="development">
        <!--jdbc 事物管理 -->
        <transactionManager type="JDBC"></transactionManager>
        <!-- 配置数据库连接信息 -->
        <dataSource type="POOLED">
            <property name="driver" value="${database.driver}"/>
            <property name="url" value="${database.url}"/>
            <property name="username" value="${database.username}"/>
            <property name="password" value="${database.password}"/>
        </dataSource>
    </environment>
</environments>

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  // 定义一个事物对象
  Transaction tx = null;
  try {
    // 通过配置对象获取事先配置好的环境对象   这里对应了 xml 中的 environments 标签。environments 默认 develop. 所以是 develop 的 environment
    final Environment environment = configuration.getEnvironment();
    // 通过环境获取事物。在 environment 里配置了 JDBC 类型的事物 ==JdbcTransactionFactory; 如果没有配置则默认采用 ManagedTransactionFactory
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    // 构建事物对象,实际就是属性的赋值
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    // 获取执行器 BatchExecutor、ReuseExecutor、SimpleExecutor , 选择 SimpleExecutor
    // 因为默认有缓存,这里会用 CachingExecutor 包裹原始 Executor , 之后会加载各种插件
    final Executor executor = configuration.newExecutor(tx, execType);
    // 返回 DefaultSqlSession。写死
    return new DefaultSqlSession(configuration, executor, autoCommit);
  } catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()
    throw ExceptionFactory.wrapException("Error opening session.  Cause:" + e, e);
  } finally {ErrorContext.instance().reset();}
}

Executor

  • Mybatis 的数据库执行器。Mybatis 提供了一共四中 Executor. 这里严格意义上应该说是三种 BatchExecutor、ReuseExecutor、SimpleExecutor。还有一个 CachingExecutor。这里为什么不把他算上了。因为这个是一个全局的开关。在 settings 标签的 cacheEnabled 设置的。说道这个标签大家都知道这个就是二级缓存的开关。所以这里 CachingExecutor 就不做介绍了。
  • SimpleExecutor 是一种常规执行器,每次执行都会创建一个 statement,用完后关闭。
  • ReuseExecutor 是可重用执行器,将 statement 存入 map 中,操作 map 中的 statement 而不会重复创建 statement。
  • BatchExecutor 是批处理型执行器,doUpdate 预处理存储过程或批处理操作,doQuery 提交并执行过程。
  • 关于 Executor 的选取也是在 settings 标签控制的。defaultExecutorType。默认是 simple

SqlSession

  • 每个线程都有一个属于自己的 Sqlsession 对象。这里我们看成是一次 Connection。他的生命周期应该是一次完成的事物处理过程。他是一个线程不安全的对象。在多线程操作的时候我们需要注意事物的隔离级别。我们操作时需要注意的是每次处理玩需要将他关闭。否则会造成资源浪费。在 Mybaits 中已经通过 finnally 把我们将他释放了。

Mapper

  • Mapper 是一个接口,我们可以将 xml 看成他的一个实现类。这里的实现类虚化。通过 Java 代码的调用实际将 xml 对应的 sql 发送给数据库并获取数据结果。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  if (mapperProxyFactory == null) {throw new BindingException("Type" + type + "is not known to the MapperRegistry.");
  }
  try {return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause:" + e, e);
  }
}
  • 通过上述代码我们能够发现。在获取 Mapper 的时候先通过类型看是否被注册了。然后根据类别获取代理实例。

总结

  • 关于生命周期其实没什么重点。这一章节也比较简单。我们只需要知道我们最终需要的 Mapper。然后是如何从配置到获取 Mapper. 这过程中哪些是全局的。哪些又适合做成复用的。

加入战队

<span id=”addMe”> 加入战队 </span>

微信公众号

正文完
 0