likes
comments
collection
share

Mybatis流程分析(三):构建SqlSession实现Mybatis的会话管理

作者站长头像
站长
· 阅读数 42

本系列文章皆在从细节着手,由浅入深的分析Mybatis框架内部的处理逻辑,带你从一个全新的角度来认识Mybatis的工作原理。

思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。 作者:毅航😜


前言

我们可以将 Configuration理解为一个大管家,其主要用于保存Mybatis配置文件xml中的配置信息;而SqlSessionFactory则是一个SqlSession的工厂,其主要作用构建SqlSession对象。

本章我们便对SqlSessionFactory构建的SqlSession进行研究和分析。

通过工厂获取SqlSession

在之前分析中我们提到对于SqlSessionFactory工厂而言,其会调用opeanSession方法来获取一个SqlSession对象信息。

具体来看,在Mybatis内部其会首先构建一个DefaultSqlSessionFactory对象,然后调用其内部的openSession方法。更进一步,其会将构建SqlSession的逻辑委托给DefaultSqlSessionFactory中的openSessionFromDataSource方法来完成。其内部代码逻辑如下所示:

DefaultSqlSessionFactory # openSessionFromDataSource


public SqlSession openSession() {
  return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
 }

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    // 获取mybatis.xml配置文件中的Environment的配置环境信息
    final Environment environment = configuration.getEnvironment();
    // 根据environment下的配置信息,构建一个事务管理器工厂
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    // 通过通常构建一个事务管理器工厂
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

    // 构建Executor执行器
    final Executor executor = configuration.newExecutor(tx, execType);
    // 返回一个DefaultSqlSessionFactory
    return new DefaultSqlSession(configuration, executor, autoCommit);    
  }

可以看到,openSessionFromDataSource内部在构建SqlSession时,需要三个成员信息,其中:

  1. ConfigurationMybatis全部的配置信息的对象
  2. Executor: Mybatis的执行器
  3. autoCommit: 一个Boolean类型变量,默认传入为false

进一步,Mybatis内部获取SqlSession对象的整个流程调用关系可总结为下图所示内容:

Mybatis流程分析(三):构建SqlSession实现Mybatis的会话管理

(注:Executor后续会单独一章进行分析,此处只需了解)

SqlSession相关内容

分析完SqlSession的构建后,我们再来看看这个SqlSession到底会完成哪些功能

事实上,SqlSessionSqlSessionFactory一样其也为一个接口。其内部定义的方法如下所示:

SqlSession接口


public interface SqlSession extends Closeable {

<T> T selectOne(String statement);

<T> T selectOne(String statement, Object parameter);


<E> List<E> selectList(String statement);

 // .... 省略其他方法,如:selectxx、insert、update、delete、commit、rollback等

我们注意到SqlSession内部除了定义一些selectxxx方法,还会包含一些insert、update、delete方法。而这些方法入参为一个String字符串信息。

虽然目前我们并不知道这些方法的相关作用,但是通过对方法名的分析,我们有理由猜测其可能同数据库相关有所关系。有这样猜测的原因主要出于以下几点:

  1. 首先,在操纵数据库的DML语言完成对数据库的操纵时,我们所写的sql通常都为select、insert、update。在结合Mybatis作为一款同数据库交互的框架来看,我们完全有理由猜测此处的方法信息可能与数据库的交互有关。

  2. 其次,我们以其中selectOne为例来看,其入参为一个名为statement字符串。熟悉jdbc开发者应该知道,在操纵数据库我们通常会构建一个Statement对象,用以执行执行sql语句,并返回结果对象。而框架中对于变量信息的命名通常都会做到见名知意,所以此处传入的信息很可能为sql语句。

结合上述两点,我们得出分析得出SqlSession 中定义的方法很可能与sql执行息息相关。

接下来,我们便进入到SqlSession的具体实现类DefaultSqlSession中,看看该方法实现的逻辑是否如我们猜想的那样。

默认实现:DefaultSqlSession

DefaultSqlSession的代码信息如下所示:

public class DefaultSqlSession implements SqlSession {

  private final Configuration configuration;
  private final Executor executor;

  @Override
  public <T> T selectOne(String statement, 
                                Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    List<T> list = this.selectList(statement, parameter);
    
  }

  public <E> List<E> selectList(String statement, 
                Object parameter, RowBounds rowBounds) {
   
      MappedStatement ms = configuration.getMappedStatement(statement);
      // 交给执行器执行
      return executor.query(ms, wrapCollection(parameter), 
  }
  // .....省略其他方法实现
}

我们注意到,SqlSession内部会持有Configuration、Executor对象,并且在构建一个DefaultSqlSession时必须将这些对象传入构造器,否则将无法创建DefaultSqlSession对象。

而前面我们在构建SqlSession中提到过,其在构建时会传入Configuration、Executor等信息。相信看到这里,你对于DefaultSqlSession构建的理解肯定会更加深刻。这些传入的对象的信息,统统都被被设定为SqlSession的成员变量。

此外,我们注意到其中的SelectList方法在实现时,会将执行逻辑委托于Executor中的query方法执行。

而在 MyBatis 中,执行器Executor 是一个关键的组件,它的作用是管理 SQL 语句的执行过程。进一步,MyBatis 使用 Executor 来协调数据库的访问,以及将 SQL 语句映射到对应的数据库操作。ExecutorMyBatis 中起到了桥梁的作用,连接了应用程序和数据库之间的交互。

进一步,Executor 的主要作用总结为如下过程:

  1. SQL 语句的执行Executor 负责将 MyBatis 的映射文件中定义的SQL 语句转化为实际的数据库操作,例如查询、插入、更新、删除等。
  2. 缓存管理:Executor 在执行 SQL 语句时,会参与 MyBatis 的缓存机制。根据缓存配置,Executor 可以从缓存中获取已经缓存的结果,避免不必要的数据库访问。
  3. 结果处理Executor 将数据库返回的结果转化为 Java 对象,以供应用程序使用。这可以包括将结果映射到对应的实体对象或集合中。
  4. 事务管理Executor 参与 MyBatis 的事务管理,确保一系列操作要么全部成功要么全部失败,保证数据的一致性。

总之,ExecutorMyBatis 中扮演着重要的角色,负责处理数据库访问的各个方面,从而实现高效、可靠的数据库操作。

至此,我们之前对于SqlSession的猜测基本基本得到了验证。事实上,在 MyBatis 中,SqlSession 是一个用于执行 SQL 操作的核心接口。它提供了与数据库的交互方法,可以执行查询、插入、更新、删除等操作。

总结

至此,我们以如下的几行简单代码为例:

//<1> 加载配置文件 
InputStream is = Resources.getResourceAsStream("mybatis.xml");  
//<2> 创建sessionFactory对象  
sessionFactory = new SqlSessionFactoryBuilder().build(is);  
//<3> 获取sqlSession对象信息 
SqlSession session = factoy.openSqlSession()

先后分析了SqlSessionFactorySqlSession的相关内容。事实上,这其实背后的逻辑很简单。总结来看就是首先new一个DefaultSqlSessionFactory对象,然后通过该对象返回一个DefaultSqlSession对象。此外,这个后续sql语句都会委托于这个DefaultSqlSession进行执行。大致逻辑如下所示: Mybatis流程分析(三):构建SqlSession实现Mybatis的会话管理

当然,Mybatis中执行Sql的故事还在继续,后续我们将继续不断深入分析探究,让你还一种视角重新认为Mybatis

转载自:https://juejin.cn/post/7269070543881175075
评论
请登录