1、根据JDBC规范建立与数据库的连接
2、通过反射打通Java对象与数据库参数交互之间相互转化关系
SqlSessionFactoryBuilder类通过各种构造器方法,将所有的配置信息维持在Configuration类中,返回一个SqlSessionFactory;SqlSessionFactory中的openSession方法会产生一个SqlSession的会话,SqlSession这边就到了CRUD操作了,然而具体的执行者却是实现了Executor接口的各种类。具体的初始化过程在下面的4.1里会详诉
在别人的博客的里看到一张图,画的很好直接拿来用了,虽然叫层次图,但是应该叫执行过程更合适一点:
图片出自 《深入理解mybatis原理》 MyBatis的架构设计以及实例分析
Mybatis的初始化的过程就是解析配置文件和初始化Configuration的过程,通过流加载mybatis的配置文件(其中加载关联的映射文件),然后SqlSessionFactoryBuilder类构建SQLSession的工厂,即创建SqlSessionFactory建造者对象(这里用到的是建造者模式)。
在这个过程中,XMLConfigBuilder对象会对XML配置文件进行解析,依次解析properties/settings/../mappers等节点配置,在解析environments节点时,会根据transactionManager的配置来创建事务管理器,根据DataSource的配置来创建DataSource对象,这里面包含了数据库登陆的相关信息。
在解析mapper节点时,会读取该节点下所有的mapper文件,然后进行解析,并将解析后的结果存到configuration对象中,生成Configuration对象,然后根据Configuration对象来创建SqlSession,到这里时,mybatis的初始化就完成了。
前面我们概括Mybatis主要干的事情就是两件:根据JDBC规范建立与数据库的连接和通过反射打通Java对象与数据库参数交互之间相互转化关系,下面就来解析具体的查询流程。
查询的API接口是在SqlSession中声明的,创建SqlSession的过程其实就是根据Configuration中的配置来创建对应的类,然后调用SqlSession中selectOne方法进行SQL查询,selectOne方法最后调用的是selectList,selectList查询configuration中存储的MappedStatement对象,mapper文件sql语句配置对应MappedStatement
对象,调用执行器进行查询操作。
执行器在query操作中,优先会查询缓存是否命中,命中则直接返回,否则从数据库中查询。真正的doQuery操作是有SimplyExecutor代理来完成的,该方法中有2个子流程,一个是SQL参数的设置,另一个是SQL查询操作和结果集的封装。
获取和数据库connection的连接,然后准备Statement,然后就是设置SQL查询中的参数值。
// SimpleExecutor类
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
// DefaultParameterHandler类
public void setParameters(PreparedStatement ps) {
......
}
ResultSetWrapper是ResultSet的包装类,调用getFirstResultSet方法获取第一个ResultSet,同时获取数据库的MetaData数据,包括数据库列名、列的类型、类序号等,这些信息都存储在ResultSetWrapper类中了,然后调用handleResultSet方法来进行结果集的封装。
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List
结果值的设置在方法handleRowValues中。
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
// 封装数据
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
然后会将表中字段的类型和java中类型一一对应起来,并最后通过java类中对应的set方法,封装java类结果集。