Mybatis框架及原理分析

框架主要类层次结构

1、Mybatis主要做的工作:

1、根据JDBC规范建立与数据库的连接
2、通过反射打通Java对象与数据库参数交互之间相互转化关系

2、主要类的层次关系

SqlSessionFactoryBuilder类通过各种构造器方法,将所有的配置信息维持在Configuration类中,返回一个SqlSessionFactory;SqlSessionFactory中的openSession方法会产生一个SqlSession的会话,SqlSession这边就到了CRUD操作了,然而具体的执行者却是实现了Executor接口的各种类。具体的初始化过程在下面的4.1里会详诉
Mybatis框架及原理分析_第1张图片

3、主要的类

  • SqlSession:作为mybatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
  • Executor:mybatis执行器,是mybatis调度的核心,赋值SQL语句的生成和查询缓存的维护
  • StatementHandler:封装了JDBC Statement操作,负责对JDBC statement的操作,如设置参数、将Statement结果集转换成list集合
  • ParameterHandler:负责对用户传递的参数转换成JDBC Statement所需要的参数
  • ResultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
  • TypeHandler:负责java数据类型和jdbc数据类型之间的映射和转换
  • MappedStatement:维护了一条< select|update|delete|insert>节点的封装
  • SqlSource:负责根据用户传递的parameterObject,动态地生成SQL语句, 将信息封装到BoundSql对象中,并返回
  • BoundSql:表示动态生成的SQL语句以及相应的参数信息
  • Configuration:MyBatis所有的配置信息都维持在Configuration对象之中

4、执行过程

在别人的博客的里看到一张图,画的很好直接拿来用了,虽然叫层次图,但是应该叫执行过程更合适一点:
Mybatis框架及原理分析_第2张图片

图片出自 《深入理解mybatis原理》 MyBatis的架构设计以及实例分析

4.1、初始化

Mybatis的初始化的过程就是解析配置文件和初始化Configuration的过程,通过流加载mybatis的配置文件(其中加载关联的映射文件),然后SqlSessionFactoryBuilder类构建SQLSession的工厂,即创建SqlSessionFactory建造者对象(这里用到的是建造者模式)。
Mybatis框架及原理分析_第3张图片

在这个过程中,XMLConfigBuilder对象会对XML配置文件进行解析,依次解析properties/settings/../mappers等节点配置,在解析environments节点时,会根据transactionManager的配置来创建事务管理器,根据DataSource的配置来创建DataSource对象,这里面包含了数据库登陆的相关信息。

在解析mapper节点时,会读取该节点下所有的mapper文件,然后进行解析,并将解析后的结果存到configuration对象中,生成Configuration对象,然后根据Configuration对象来创建SqlSession,到这里时,mybatis的初始化就完成了。

4.2、Mybatis的Sql查询流程

前面我们概括Mybatis主要干的事情就是两件:根据JDBC规范建立与数据库的连接和通过反射打通Java对象与数据库参数交互之间相互转化关系,下面就来解析具体的查询流程。
查询的API接口是在SqlSession中声明的,创建SqlSession的过程其实就是根据Configuration中的配置来创建对应的类,然后调用SqlSession中selectOne方法进行SQL查询,selectOne方法最后调用的是selectList,selectList查询configuration中存储的MappedStatement对象,mapper文件sql语句配置对应MappedStatement
对象,调用执行器进行查询操作。
执行器在query操作中,优先会查询缓存是否命中,命中则直接返回,否则从数据库中查询。真正的doQuery操作是有SimplyExecutor代理来完成的,该方法中有2个子流程,一个是SQL参数的设置,另一个是SQL查询操作和结果集的封装。

4.2.1、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) {
    ......
}
4.2.1、SQL查询结果集的封装

ResultSetWrapper是ResultSet的包装类,调用getFirstResultSet方法获取第一个ResultSet,同时获取数据库的MetaData数据,包括数据库列名、列的类型、类序号等,这些信息都存储在ResultSetWrapper类中了,然后调用handleResultSet方法来进行结果集的封装。

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
        if (parentMapping != null) {
            handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
        } else {
            if (resultHandler == null) {
                DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
                handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
                multipleResults.add(defaultResultHandler.getResultList());
            } else {
                handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
            }
        }
    } finally {
        closeResultSet(rsw.getResultSet());
    }
}

结果值的设置在方法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类结果集。

你可能感兴趣的:(WEB总结)