SqlSessionExePro

Mybatis SqlSession 执行SQL流程

在看源码之前,我们需要了解一些基本知识

SqlSession

SqlSession是一个接口,它有两个实现类:
	- DefaultSqlSession:默认实现类
	- SqlSessionManager:已经弃用的实现类,所以我们不需要关注他
SqlSession是与数据库交互的顶层类,通常与ThreadLocal绑定,一个会话使用一个SqlSession,SqlSession是线程不安全的,使用完毕需要close()

public class DefaultSqlSession implements SqlSession {
	private final Configuration configuration;
	private final Executor executor;
}
SqlSession中最重要的两个变量:
	- Configuration:核心配置类,也是初始化时传过来的
	- Executor:实际执行SQL的执行器

Executor

Executor是一个接口,有三个实现类
	- BatchExecutor 重用语句,并执行批量更新
	- ReuseExecutor 重用预处理语句prepared statements
	- SimpleExecutor 普通的执行器,默认使用

了解完基本知识后,我们接着往下看代码。

当创建完SqlSessionFactory后,就可以创建SqlSession,然后使用SqlSession进行增删改查:

我们先去看openSession()方法,创建了SqlSession

通过源码可以清晰的看到,会话工厂创建了EnvironmentTransactionExecutorDefaultSqlSession对象,并且对于会话对象来说,他的autoCommit默认为false,默认不自动提交。

然后我回到原来的代码,接着就需要使用SqlSession进行增删改查操作了

所以我们进入selectList()查看

selectList有多个重载方法,进入到最终方法后,我们可以看到它做了两件事

  • 通过statementId,从Configuration中取MappedStatement对象,就是存放了sql语句,返回值类型,输入值类型的对象

  • 然后委派Executor执行器去执行具体的增删改查方法

所以,对于实际JDBC的操作,我们还需要进入Executor中查看

Mybatis之Executor

我们继续从刚刚selectList源码中,进入Executor查看

拆分成了三大步:

(1)先调用MappedStatementgetBoundSql方法,获取解析后的SQL语句,解析工作是由SqlSourceBuilder完成的

什么叫解析后的SQL语句呢?因为Mybatis编写SQL语句时,会用到动态SQL,比如#{}占位符,这种占位符JDBC是不认识的,所以需要将其转换成占位符,并且将其内部的字段名存储起来,后面填充参数的时候好使用反射获取值。

上面代码就可以看到,会将拆分#{},进行解析

(2)根据查询条件,创建缓存key,用来接下来去缓存查找是否有已经执行过的结果

(3)调用重载query()方法

接着我们进入重载方法查看:

主要的逻辑:

  • 从一级缓存取数据,如果有直接使用缓存的进行接下来的操作

  • 如果没有,从数据库查询

进入queryFromDatabase()方法:

通过代码可以看到,对于实际与JDBC交互的代码,Executor也懒得搞,又像SqlSession一样,委派给小弟StatementHandler了。

Mybatis之StatementHandler

我们从刚刚的Executor的代码查看

可以看到,这里创建完StatementHandler后,回调用prepareStatement()方法,用来创建Statement对象

我们进入prepareStatement方法中查看

这里可以看到,它实际是使用ParameterHandler来设置Statement的参数

这段代码的主要目的,就是获取入参,然后根据值,来设置占位符的参数

TypeHandler是具体进行参数设置的对象

所以handler.prepare(connection, transaction.getTimeout());方法,就是使用ParameterHandler来对占位符位置的参数进行值设置

然后我们回到Executor,查看handler.query()方法

代码很简单,这里直接使用JDBC的PreparedStatement来进行SQL执行,然后使用ResultSetHandler进行结果数据封装处理。

进入ResultSetHandler

代码比较多,实际最重要的代码就是

将处理后的结果封装到集合中返回,这样基本Mybatis逻辑就走完了.

我们来回顾一下,都用到了哪些类

sqlSession

简单总结

SqlSessionFactoryBuilder:

  • 解析核心配置文件,创建Configuration

    • XMLConfigBuilder.parse():解析核心配置文件

    • XMLMapperBuilder.parse():解析映射配置文件MappedStatement

  • 创建SqlSessionFactory,默认创建DefaultSqlSessionFactory

SqlSessionFactory:

  • openSession():构建Executor,SqlSession等

SqlSession:

  • 根据statementId获取MappedStatement

  • 委派给Executor执行器执行

Executor:

  • 使用SqlSourceBuilder,将SQL解析成JDBC认可的

  • 查询缓存,是否存在结果

  • 结果不存在,委派给StatementHandler处理器

StatementHandler:

  • PreparedStatement:处理参数,将参数赋值到占位符上

    • TypeHandler:具体设置值的类

  • ResultSetHandler:封装结果集,封装成设置的返回值类型

    • TypeHandler:根据结果集,取出对应列

Last updated

Was this helpful?