1.概述
在之前的两篇博客《mybatis原理分析(一)—JDBC》和《mybatis原理分析(二)—深入理解Executor》中分别详细的介绍了JDBC的特点和使用以及mybtias中的重要组件Executor,如果不太了解的读者不妨去阅读一下这两篇博客,我相信会给你带来收获。
这两者是通过什么联系起来的呢?
在mybatis中,Executor会创建一个StatementHandler,而JDBC的相关操作全部放到了这个StatementHandler中。
在一次sql会话中,会创建一个Executor,而Executor会根据不同的sql请求,创建不同的StatementHandler去执行JDBC访问数据库。一次会话中三者的数量关系是1:1:N。
2.StatementHandler相关介绍
定义:JDBC处理器,基于JDBC构建JDBC Statement,并设置参数,然后执行Sql。每调用会话当中一次SQl,都会有与之相对应的且唯一的Statement实例。
public interface StatementHandler {
// 构建一个Statement
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
// 设置参数
void parameterize(Statement statement)
throws SQLException;
// 添加批处理
void batch(Statement statement)
throws SQLException;
// 执行update操作
int update(Statement statement)
throws SQLException;
// 执行query操作
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
// 执行queryCursor操作
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
// 获取sql
BoundSql getBoundSql();
//获取参数处理器
ParameterHandler getParameterHandler();
}
类图如下:
有两个直接的实现类,BaseStatementHandler和RoutingStatementHandler。
BaseStatementHandler 是一个抽象类,并没有实现StatementHandler接口定义的所有的方法,只是实现了它下面三个子类有共性的方法,例如prepare 声明statement,setStatementTimeout 设置超时时间,setFetchSize 设置数据库返回行数等。BaseStatementHandler有三个子类,三个子类分别对应了JDBC中的三种Statement。
RoutingStatementHandler 主要就是用来根据不同的Statement类型选择构建不同的StatementHandler。
3. 构建StatementHandler
在mybatis中是什么时候,又是如何创建StatementHandler的呢?
编写如下测试代码
/**
* @author gongsenlin
* @version 1.0
* @date 2020-09-24 12:56
*/
public class StatementHandlerTest {
private Configuration configuration;
private JdbcTransaction jdbcTransaction;
@Before
public void init() {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder
.build(StatementHandlerTest.class.getResourceAsStream("/mybatis-config.xml"));
configuration = sessionFactory.getConfiguration();
jdbcTransaction = new JdbcTransaction(sessionFactory.openSession().getConnection());
}
@Test
public void test1() throws SQLException {
SimpleExecutor simpleExecutor = new SimpleExecutor(configuration, jdbcTransaction);
MappedStatement mappedStatement = configuration.
getMappedStatement("com.gongsenlin.executor.dao.UserMapper.selectByid");
List<Object> list = simpleExecutor.doQuery(mappedStatement, 10,
RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, mappedStatement.getBoundSql(10));
}
}
将断点定位到simpleExecutor.doQuery这一行。进入doQuery方法
在这个方法里,configuration.newStatementHandler就是用来构建StatementHandler。
首先会构建一个RoutingStatementHandler
在它的构造函数里面,就会根据statement的类型,构建对应的StatementHandler。而默认的statement的类型是“PREPARED”
可以通过添加注解或者xml中配置的方式来修改Statement的类型
综上,StatementHandler是在Executor中,执行doQuery或doUpdate等方法的时候,会根据配置的不同类型进行创建不同的StatementHandler,默认是PreparedStatementHandler。
三个子类的逻辑很简单,就是封装了JDBC的操作,了解三个子类的不同点,可以从了解JDBC中三种Statement的不同点开始,可以看看这篇博客《mybatis原理分析(一)—JDBC》
4. 后续
接下来博客更新将会是关于参数处理以及结果集处理相关的内容。