1、StatementHandler对象的创建过程
在上一节MyBatis源码学习—MyBatis 执行器Executor详解中我们了解MyBatis执行器的产生以及执行SQL的大致过程。StatementHandler 对象是在 SqlSession 对象接收到SQL执行命令时,由 Configuration 对象中的newStatementHandler 负责调用的,也就是说 Configuration 中的 newStatementHandler 是由执行器中的查询、更新(插入、更新、删除)方法来提供的,StatementHandler 其实就是由 Executor 负责管理和创建的。
以查询为例,在SimpleExecutor中最终落到了doQuery()
这个方法,如下图所示。
在执行查询逻辑中比较重要的异步操作就是StatementHandler handler = configuration.newStatementHandler(......)
这一句代码,从字面意思看,它就是创建了一个StatementHandler实例对象,一个用来执行SQL查询的处理器。
追进去看看newStatementHandler方法干了什么,如下图所示Configuration类的newStatementHandler方法。
可以看到他直接为我们new了一个RoutingStatementHandler对象,然后返回了这个对象。RoutingStatementHandler在下面会详细介绍,别着急!!!
2、StatementHandler继承结构
和Executor体系的继承体系类似,最顶层的接口是StatementHandler,往下有2个直接实现类:BaseStatementHandler和RoutingStatementHandler,BaseStatementHandler又有3个子类:PreparedStatementHandler、SimpleStatementHandler以及CallableStatementHandler
StatementHandler:MyBatis四大组件中最重要的一个对象,负责操作 Statement 对象(JDBC)与数据库进行交流,在工作时还会使用 ParameterHandler 和 ResultSetHandler 对参数进行映射,对结果进行实体类的绑定。
StatementHandler其实就是对JDBC中Statement的包装,为了一探究竟我们直接打开MyBatis源码来看一下。下图所示是StatementHandler接口的方法。
- prepare():用于创建一个具体的Statement对象的实现类实例
- parameterize():用于初始化Statement实例对象以及对SQL语句中的占位符进行数据填充
- update():用于通知Statement对象将insert、update、delete操作发送给数据库
- query():用于通知Statement对象将select操作发送到数据库
RoutingStatementHandler:从它的名字就可以窥见它的作用,它的作用就是选择合适的StatementHandler实现类的,具体就是根据StatementType 参数来创建一个代理,代理的就是对应Handler的三种实现类
看到这里,是不是对RoutingStatementHandler这个类的作用恍然大悟~~他就类似 与一个路由器,把一条SQL请求路由到一个具体的StatementHandler实现类去
BaseStatementHandler:是StatementHandler接口的另一个实现类,本身是一个抽象类,用于简化StatementHandler 接口实现的难度,属于适配器设计模式体现,它主要有三个实现类:
- SimpleStatementHandler:用于处理不需要预编译的SQL语句,类似于JDBC中普通的Statement
- PraparedStatementHandler:用于处理不需要预编译的SQL语句,类似于JDBC中的PraparedStatement
- CallableStatementHandler:用于处理存储过程,类似JDBC中的CallableStatement
3、StatementHandler核心方法源码分析
prepare方法调用流程分析
执行器 Executor 在执行SQL语句的时候会创建 StatementHandler 对象,进而经过一系列的 StatementHandler 类型的判断并初始化。再拿到StatementHandler 返回的 statementhandler 对象的时候,会调用其prepareStatement()
方法,下面就来一起看一下 preparedStatement()
方法
从Executor的doQuery方法开始,首先实例化一个Statement对象,其实就是RoutingStatementHandler,在RoutingStatementHandler内部维护了一个真实干活的StatementHandler对象。实例化完成后,调用了执行器的prepareStatement方法获取数据库连接Connetion,紧接着调用了StatementHandler的prepare方法,这个调用首先会到RoutingStatementHandler中的同名方法,之后会调到BaseStatementHandler中,这个方法只在BaseStatementHandler有具体实现,在这个实现中,它又调用了**instantiateStatement **,这个方法在BaseStatementHandler没有具体实现,实际执行的是三种 StatementHandler 中的一种,我们还以 SimpleStatementHandler
为例
protected Statement instantiateStatement(Connection connection) throws SQLException {
if (mappedStatement.getResultSetType() != null) {
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.createStatement();
}
}
从上面代码我们可以看到,instantiateStatement() 最终返回的是Statement对象,经过一系列的调用会把Statement 对象返回到 SimpleExecutor 执行器中,为 parametersize 方法所用。也就是说,prepare 方法负责生成 Statement 实例对象,而 parameterize 方法用于处理 Statement 实例对应的参数。
parametersize 方法调用流程分析
在上面的prepareStatement方法中执行器拿到具体的Statement对象实例之后就会调用parametersize方法用处理Statement实例的参数
对于这个SimpleStatementHanlder在前面我们说过他就是用来处理简单SQL语句的,因此它的实现方法是空的,如下图所示。
因此具体的原理我们着重看PraparedStatementHandler的同名方法的实现,如下图所示。
可以看到,具体给SQL语句参数赋值的操作MyBatis有把它交给了下一个组件ParameterHandler(参数处理器),具体内容请参考我的下一篇博文:MyBatis源码学习—MyBatis参数处理器ParameterHandler详解
query 方法调用流程分析
StatementHandler中query方法是用于执行SQL查询语句的方法,它的具体实现在BaseStatementHandler中没有实现,我们以SimpleStatementHandler为例来分析一下。下图所示是SimpleStatementHandler的query方法。
流程非常简单暴力:获取到sql语句=>调用Statement的execute方法执行sql=>调用结果处理器封装查询结果。具体查询结果集封装返回值的类容请参考我的博文:MyBatis源码学习—MyBatis结果处理器ResultHandler详解
update 方法调用流程分析
StatementHandler的update方法是用于SQL语句的insert、update、delete语句的执行,我们以SimpleStatementHandler为例来分析一下。下图所示是SimpleStatementHandler的update方法。
简单描述一下update 方法的执行过程:
- MyBatis 接收到 update 请求后会先找到 CachingExecutor 缓存执行器查询是否需要刷新缓存,然后找到BaseExecutor 执行 update 方法;
- BaseExecutor 基础执行器会清空一级缓存,然后交给再根据执行器的类型找到对应的执行器,继续执行 update 方法;
- 具体的执行器会先创建 Configuration 对象,根据 Configuration 对象调用 newStatementHandler 方法,返回 statementHandler 的句柄;
- 具体的执行器会调用 prepareStatement 方法,找到本类的 prepareStatement 方法后,再有prepareStatement 方法调用 StatementHandler 的子类 BaseStatementHandler 中的 prepare 方法
- BaseStatementHandler 中的 prepare 方法会调用 instantiateStatement 实例化具体的 Statement 对象并返回给具体的执行器对象
- 由具体的执行器对象调用 parameterize 方法给参数进行赋值。
用一幅图来表示一下这个调用过程:
参考资料
- [1] https://www.cnblogs.com/cxuanBlog/p/11295488.html