首页 > 编程语言 >MyBatis源码分析(二)prepareStatement预编译的执行流程

MyBatis源码分析(二)prepareStatement预编译的执行流程

时间:2022-12-21 12:07:56浏览次数:41  
标签:执行器 executorType prepareStatement sql Mybatis 源码 executor MyBatis Executor


通常我们如果自己写建立数据库连接的代码的时候,都会这么写

pstmt = conn.prepareStatement(sql);
pstmt.setString(1, email);
result = pstmt.executeQuery();

而Mybatis是怎么封装,又是怎么进行预编译的呢,今天就一文让你理解Mybatis的原理

一、获取Executor

我们之前一篇文章​​《MyBatis源码分析(一)基本请求流程》​​讲了Mybatis执行的基本流程,包括Plugin插件。
其实在执行过程中,所有的sql语句都要经过执行器Executor。执行器创建的源码如下:

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
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);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}

可以看到创建的执行器有三种,分别是

  • BatchExecutor:批量执行的执行器,官方说明这个executor是用于执行存储过程的和批量操作的,因此这个方法是循环或者多次执行构建一个存储过程或批处理过程。BatchExecutor 的事务是没法自动提交的。因为 BatchExecutor 只有在调用了 SqlSession 的 commit 方法的时候 , 它才会去执行 executeBatch 方法。这个执行器基本用不到,现在的正常的公司都不允许搞存储过程。
  • ReuseExecutor:会缓存创建的prepareStatement,但是只能在同一个sqlSession中,用处不大,待会说prepareStatement还会再介绍这个执行器。
  • SimpleExecutor:是默认的执行器,这个执行器是在什么地方指定的呢,在Configuration类中:
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

以上的三个Executor都有同一个父类:BaseExecutor,在BaseExecutor的query方法中,调用了三个子类的doQuery方法,update方法中,调用了三个子类的doUpdate方法,这是用了模板方法设计模式

二、SqlSession

SqlSession是一次数据库连接,在Mybatis中,是通过如下方式创建的:

MyBatis源码分析(二)prepareStatement预编译的执行流程_源码


同时也可以看到,一个SqlSession对应创建一个新的执行器Executor。这也是为什么我们上面说ReuseExecutor没有什么用处的原因,在Mybatis中一个sql语句就会创建一个SqlSession,创建一个执行器Executor,ReuseExecutor就算缓存了PrepareStatement也用不上。

三、关闭连接

在执行sql的时候,会调用到SqlSessionTemplate,这是一个模板方法的类。在invoke方法执行完后,会调用finally方法关闭连接:

} finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}

}

这个方法中调用了session.close(),里面又调用了executor.close()方法去关闭SqlSession,Executor从而关闭SqlSession,释放连接。

四、SimpleExecutor

SimpleExecutor是Mybatis默认使用的执行器,其doQuery方法如下:

@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}

可以看到里面限制性的prepareStatement方法,然后又执行了query方法。
prepareStatement方法里面其实就是封装了我们手动创建PrepareStatement的时候的conn.prepareStatement方法,先去进行预编译,预编译完成后,在调用query方法执行。
由此可见Mybatis底层还是用的我们自己创建Statement并执行sql语句的方法。

五、SqlNode

在Mybatis中,我们都要写xml文件,例如这样一段xml写的sql:

<select id="selectByIdList" resultMap="BaseResultMap" parameterType="Long" >
select
<include refid="Base_Column_List" />
from table_1
where id in
<foreach collection="list" item="status_id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>

Mybatis是怎么把这样的语句解析成sql语句的呢,就是通过SqlNode,SqlNode是一个接口类,它有很多子类

MyBatis源码分析(二)prepareStatement预编译的执行流程_mybatis_02


例如IfSqlNode就是用来解析Mybatis文件下面的 <if 标签,其入口就是在MappedStatement.getBoundSql方法中,经过一系列SqlNode解析后,就变成了一条正常的sql语句。

六、总结

本篇文章主要向你介绍了执行sql的一些关键节点:

  • Executor:执行有有BatchExecutor、SimpleExecutor、ReuseExecutor,这三个执行器默认的同时也是最常用的是SimpleExecutor
  • SqlSession: 在Mybatis中正常情况下执行sql的会话,sql执行完则关闭此会话,同时还会关闭对应的执行器。
  • SqlNode:在Mybatis中的xml语法,怎么解析成Sql语句呢?就是通过SqlNode

在读了这篇文章后,你是不是对Mybatis的原理理解地非常深入了呢?为了让你更好的进行开发工作,博主创建了一篇专栏教你精通使用在工作过程中的各种工具:​​《精通java开发工具》​​快来提升你的工作效率吧。


标签:执行器,executorType,prepareStatement,sql,Mybatis,源码,executor,MyBatis,Executor
From: https://blog.51cto.com/u_11970680/5959681

相关文章

  • JDK源码之CompletableFuture(二)链式调用原理
    ​​JDK源码之CompletableFuture(一)结果返回原理​​JDK源码之CompletableFuture(二)链式调用原理JDK源码之CompletableFuture(三)anyOf,allOf是怎么实现的?目录​​一、第一步调......
  • SpringMVC父子容器加载与关系源码
    我们都知道SpringMVC父子容器加载是通过dispatcherServlet与ContextLoaderListener类:他们的关系源码如下:先说父容器加载:Context'Loader'Listener源码如下:@Overridepublic......
  • AliMQ(RocketMQ)源码(一)创建producer
    公司现在在使用阿里云的AliMQ也就是RocketMQ,趁着工作之余,将RocketMQ的使用心得分析一下,关于RocketMQ的Producer、Consumer、Broker、NameServer等架构问题,在此处先不做分析......
  • AliMQ(RocketMQ)源码(二)producer.start()
    在创建完成Producer后,就进入了Producer的start()方法。start()方法DefaultMQProducerImpl的start()方法。this.serviceState=ServiceState.START_FAILED;......
  • mybatis缓存
    Mybatis中缓存分为一级缓存,二级缓存。一级缓存一级缓存是SqlSession级别的缓存,只要SqlSession没有flush或close,它就存在默认开启并使用当调用SqlSession的修......
  • mybatis-plus的分页
    mybatis-plus包含内置的分页插件,我们要做的就是配置拦截器,然后使用内置的分页类就可以了。配置Interceptor分页的使用QueryWrapper指定查询条件Page指定获取特定......
  • Mybatis 连接池,事务,动态sql
    1、连接池pooled用连接池unpooled不用连接池<dataSourcetype="POOLED"><propertyname="driver"value="${jdbc.driver}"/><propertyname="url"value="${jdbc.ur......
  • 基于Java springboot+mybatis+mysql+jsp网上书城管理系统
    @目录一、系统介绍二、功能展示1.主页(客户)2.登陆(客户)3.我的购物车(客户)4.我的订单(客户)5.我的图书(商家)6.新书上架(商家)7.订单管理(商家)7.统计分析(管理员)8.用户管理(用户管理......
  • 基于springboot+mybatis+vue软件缺陷管理系统
    @目录一、系统介绍二、功能展示1.主页2.个人中心3.缺陷管理4.项目管理5.系统管理6.统计分析三、代码展示四、获取源码一、系统介绍系统主要功能:开发人员:主页、个人中心(......
  • 基于Spring+SpringMVC+Mybatis+Mysql在线考试系统
    @目录一、系统介绍二、功能展示1.用户登陆2.学生页面3.考试信息(老师)4.试卷库(老师)5.试题库(老师)6.考生信息(老师)7.成绩分析(老师)8.成绩排名(老师)9.错题统计(老师)10.成绩导出(老......