我们处于的位置

我们要清楚现在的情况.

现在我们已经调用了SqlSessionFactoryBuilder的build方法生成了SqlSessionFactory 对象.

但是如标题所说,要想生成sqlsession还要另一步SqlSessionFactory 调用openSession()方法生成sqlsession;

这就要从上一部分代码讲起

上文讲到

我们创建的实际上是一个叫做DefaultSqlSessionFactory的类,实际上他是一个SqlSessionFactory接口(没错,这玩应是接口)的实现类.

既然sqlsession是由opensession产生的,那我们就先看这个方法.

说一嘴题外话就是自动提交也是在这个部分设置的,下面是如果你设置了autocommit的情况.

public SqlSession openSession(boolean autoCommit) {
//this.configuration.getDefaultExecutorType()值为 ExecutorType.SIMPLE;
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
}

参数中 configuration 获取了默认的执行器 “SIMPLE”.


DefaultSqlSessionFactory

调用了一个同一个类中openSessionFromDataSource方法.

在这个类中是如下执行流程

所要知道的一部分知识.

environments运行环境

MyBatis 核心配置综述之 Configuration详解

其实就是数据库连接那个部分.

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//从configuration对象中得到环境配置的对象
final Environment environment = configuration.getEnvironment();
//这个对象被用来创建一个事务工厂->一号分支
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//事务工厂创建一个事务对象->二号分支
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//而 configurationye 则会根据事务对象和执行器类型创建一个执行器。
->三号分支
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();
}
}

现在我们要从一号分支开始


一号分支

final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);

这个代码如下:

我们发现有两种可能性.

如果传进来的值没有设置标签那么他会执行ManagedTransactionFactory()而反之则会执行environment.getTransactionFactory()

这两者产生的对象都实现了 TransactionFactory接口.

这里ManagedTransactionFactory()是没有标签时生成的对象.其核心就是一句

private boolean closeConnection = true;的属性.

我们不必过于关注这个部分.

private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
//如果没有目标标签
return new ManagedTransactionFactory();
}
//如果有目标标签
return environment.getTransactionFactory();
}

environment.getTransactionFactory()产生的东西才是重点.

调用环境对象的getTransactionFactory方法,该方法和我们配置的一样返回了一个 JdbcTransactionFactory,而实际上,TransactionFactory 只有2个实现类,一个是 ManagedTransactionFactory (没有标签时返回的),一个是 JdbcTransactionFactory(有标签时返回的)。

至此一号分支结束,从此看来,一号分支实际上是将environment对象包装成一个工厂对象.

请返回一号分支之前部分继续.


分支二

tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

我们回到openSessionFromDataSource方法,获取了 JdbcTransactionFactory 后,调用 JdbcTransactionFactorynewTransaction方法创建一个事务对象.

当然因为代码中采用TransactionFactory 接口作为声明对象.所以无论分之一传回来的是哪个工厂对象.在分支二中都可以执行.

我们先讲 JdbcTransactionFactory的情况.

分支二中调用的是这个newTransaction方法.(还有一个重载的)

public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}

这就到了另一个类中JdbcTransaction中.

JdbcTransaction

我删掉其中的实现代码

public class JdbcTransaction implements Transaction {

  private static final Log log = LogFactory.getLog(JdbcTransaction.class);

  protected Connection connection;
protected DataSource dataSource;
protected TransactionIsolationLevel level;
protected boolean autoCommmit; public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommmit = desiredAutoCommit;
} public JdbcTransaction(Connection connection) {
this.connection = connection;
} public Connection getConnection() throws SQLException { } public void commit() throws SQLException { } public void rollback() throws SQLException { } public void close() throws SQLException { } protected void setDesiredAutoCommit(boolean desiredAutoCommit) { } protected void resetAutoCommit() { } protected void openConnection() throws SQLException { } }

其实只要看了代码你就会发现,这个类中的方法,和我们调用session的方法高度重合.比如commit,rollback等等.而且还能设置事务的隔离级别

所以我们有理由认为,这个类就是对jdbc连接部分的封装.

总结

至此分支二结束,我们对于标签在xml中的存在情况,会返回两种截然不同对象.一种是作为jdbc连接封装的JdbcTransaction对象.另一个则是ManagedTransaction对象(这个没讲....)


分支三

第三分支我们将回到Configuration对象.

Configuration对象

法此时已经创建好事务对象。接下来将事务对象执行器作为参数执行 configuration 的 newExecutor 方法来获取一个 执行器类。我们看看该方法实现:

首先第一句将判断是否传入了一个excutorType参数,如果没有就用默认的参数.

也就是 ExecutorType.SIMPLE(前面出现过),然后根据执行的类型来创建不同的执行器,默认是 SimpleExecutor 执行器.

Mybatis有三种基本的Executor执行器:

  • SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。

  • ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用。简言之,就是重复使用Statement对象。

  • BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。

然后我们看下一句部分

Executor executor;
//看看上文.这是根据传入的内容不同,最终结果是
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}

我们先将 BatchExecutor执行器.

该类包装了事务对象,延迟加载的队列,本地缓存,永久缓存,配置对象,还包装了自己。

传入的两个参数分别为存储了配置信息的Configuration对象,以及封装了jdbc中连接数据库部分代码的JdbcTransaction对象.

回到 newExecutor 方法,判断是否使用缓存,默认是true, 则将刚刚的执行器包装到新的 CachingExecutor 缓存执行器中。最后将执行器添加到所有的拦截器中(如果配置了话),我们这里没有配置。

到此分支三结束

总结:

我们从用从分支二得到的对象,构建了一个执行器.这个执行对象,包括事务对象(即连jdbc连接部分的控制封装.JdbcTransaction),延迟加载的队列,本地缓存,永久缓存,配置对象(Configuration),还包装了自己。


四号分支

我们已经有了执行器,此时创建 DefaultSqlSession 对象,携带 configuration, executor, autoCommit 三个参数,该构造器就是简单的赋值过程。我们有必要看看该类的结构:

该类包含了常用的所有方法,包括事务方法,可以说,该类封装了执行器和事务类。而执行器才是具体的执行工作人员。

至此,我们已经完成了 SqlSession 的创建过程。

Mybatis详解(二) sqlsession的创建过程的更多相关文章

  1. Android Fragment详解(二):Fragment创建及其生命周期

    Fragments的生命周期 每一个fragments 都有自己的一套生命周期回调方法和处理自己的用户输入事件. 对应生命周期可参考下图: 创建片元(Creating a Fragment) To c ...

  2. Linux 网络编程详解二(socket创建流程、多进程版)

    netstat -na | grep " --查看TCP/IP协议连接状态 //socket编程提高版--服务器 #include <stdio.h> #include < ...

  3. 【转载】详解CreateProcess调用内核创建进程的过程

    原文:详解CreateProcess调用内核创建进程的过程 昨天同学接到了腾讯的电面,有一题问到了CreateProcess创建进程的具体实现过程,他答得不怎么好吧应该是, 为了以防万一,也为了深入学 ...

  4. Android View 的绘制流程之 Layout 和 Draw 过程详解 (二)

    View 的绘制系列文章: Android View 的绘制流程之 Measure 过程详解 (一) Android View 绘制流程之 DecorView 与 ViewRootImpl 在上一篇  ...

  5. HTTPS详解二:SSL / TLS 工作原理和详细握手过程

    HTTPS 详解一:附带最精美详尽的 HTTPS 原理图 HTTPS详解二:SSL / TLS 工作原理和详细握手过程 在上篇文章HTTPS详解一中,我已经为大家介绍了 HTTPS 的详细原理和通信流 ...

  6. mybatis 详解(三)------入门实例(基于注解)

    1.创建MySQL数据库:mybatisDemo和表:user 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 2.建立一个Java工程,并导入相应的jar包,具体目录如 ...

  7. [原创]mybatis详解说明

    mybatis详解 2017-01-05MyBatis之代理开发模式1 mybatis-Dao的代理开发模式 Dao:数据访问对象 原来:定义dao接口,在定义dao的实现类 dao的代理开发模式 只 ...

  8. PopUpWindow使用详解(二)——进阶及答疑

      相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...

  9. logback -- 配置详解 -- 二 -- <appender>

    附: logback.xml实例 logback -- 配置详解 -- 一 -- <configuration>及子节点 logback -- 配置详解 -- 二 -- <appen ...

随机推荐

  1. 剑指Offer02之替换空格

    剑指Offer02之替换空格 题目描述 实现一个方法,将输入的字符串中的空格替换成%20. 例子如下 hello world --> hello%20world 代码实现 //方法一 采用Jav ...

  2. es6的数组操作

    //foreach 迭代 var arr = [1, 2, 3]; var sum = 0; arr.forEach(function(value, index, array) { console.l ...

  3. SpringMVC入门总结

    一.SpringMVC的好处? 1,基于注解,stuts2虽然也有注解但是比较慢,没人用更多的时候是用xml的形式 2,能与spring其它技术整合比如说webflow等, 3,获取request及s ...

  4. python的生成器和迭代器

    三.推倒式从时间上比较:集合 字典 元祖 列表 (从小到大)占用内存比较:字典 集合 列表 元祖 (从大到小) 字典是可进行hash操作,操作的是字典的key ,而对list进行hash操作的时候操作 ...

  5. SQL SERVER修改为sa登陆权限报错,233,18456接连出现【抓狂ing】

    [记录生活] 今天做作业需要修改sa权限,本人电脑没错误. 同样教程发给朋友,错误百出.... 话不多说,百度很多解决方法,但是都没有解决,贴出解决方法. 0.用Windows身份验证登录,执行SQL ...

  6. Linux 任务后台运行软件【即:终端复用器】之---screen

    会话: 命令行的典型使用方式是,打开一个终端窗口(terminal window,以下简称"窗口"),在里面输入命令. 用户与计算机的这种临时的交互,称为一次"会话&qu ...

  7. 【转】B树、B+树、B*树、R 树、QuadTree

    从B树.B+树.B*树谈到R 树 QuadTree(四叉树) 四叉树空间索引原理及其实现

  8. 对于使用progisp软件进行ISP编程时进入不了编程模式的解决方法

    标题: 对于使用progisp软件进行ISP编程时无法进入编程模式的解决方法 作者: 梦幻之心星 347369787@QQ.com 标签: [progisp, 软件] 目录: 软件 日期: 2019- ...

  9. SpringBoot系列—简单的邮件系统

    1. 效果发送效果图 2. 邮件开发准备工作 3. springboot引入mail服务 4. 启动应用,开始4种邮件发送测试 1. 效果发送效果图 连续发送了四封邮件:普通文本邮件,带附件的邮件,内 ...

  10. php mysqli使用

    连接到数据库$mysqli = new mysqli(主机,用户,密码,数据库); 选择数据库$mysqli->select_db(数据库);设置编码$mysqli->set_charse ...