Bootstrap

MyBatis核心流程

目录

数据处理的发展

MyBatis概述

​编辑 

MyBatis核心流程

观察测试类

重要对象和流程

SqlSessionFactory [初始化]

创建SqlSession会话对象

 

创建XxxMapper[代理]对象

执行SQL操作 [复杂一丢丢]

 ​编辑


数据处理的发展

1.原生JDBC


2. DBUtils工具类 [jdbctemp..]

3. ORM [MyBatis]

MyBatis概述

 

① MyBatis 是一款优秀的持久层框架 [ORM],它支持自定义 SQL、存储过程以及高级映射;
② MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作;
③ MyBatis 可以通过简单的 XML文件或注解 将Java对象配置和映射为数据库中的记录;
Java对象:原始类型、接口和 Java POJO [Plain Old Java Objects 普通老式Java对象]
④ MyBatis里面,SQL和代码是分离的,所以会写SQL基本上就会用MyBatis
简单而言:会写SQL语句 你就可以像进行Java编码一样,来完成数据操作 

MyBatis核心流程

观察测试类

public void test2() throws Exception{
    // 1.获取配置文件
    InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
    // 2.加载解析配置文件并获取SqlSessionFactory对象
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    // 3.根据        SqlSessionFactory对象获取SqlSession对象
    SqlSession sqlSession = factory.openSession();
    //sqlSession.selectOne("");
    // 4.通过SqlSession中提供的 API方法来操作数据库
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> list =         mapper.selectUserList();
    for (User user : list) {
        System.out.println(user);
       }
    // 5.关闭会话
    sqlSession.close();
}

重要对象和流程

代码简单,我们需要从中提取代码中出现过的重要对象,由此切入核心对象和关键流程分析:
1. SqlSessionFactory初始化
2. 创建SqlSession
3. XxxMapper [代理]
4. SQL操作

SqlSessionFactory [初始化]

获取SqlSessionFactory 对象的主干流程:

  // --SqlSessionFactoryBuilder类--// build() 重载一
    public SqlSessionFactory build(InputStream inputStream) {
        return build(inputStream, null, null);
    }
    // build() 重载二
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties
            properties) {
        try {
// 用于解析 mybatis-config.xml,同时创建了 Configuration 对象 >>
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment,properties);
// 解析XML,最终返回一个 DefaultSqlSessionFactory >>
            return build(parser.parse());
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
            ErrorContext.instance().reset();
            try {
                inputStream.close();
            } catch (IOException e) {
// Intentionally ignore. Prefer previous error.
            }
        }
    }
    // build() 重载三
    public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }

MyBatis - Builder
1. XMLConfigBuilder - 解析全局配文件
2. XMLMapperBuilder - 解析Mapper映射文件
3. XMLStatementBuilder - 解析Mapper映射文件中的数据操作节点[CURD]
4. SqlSourceBuilder - 解析SQL语句
5. XMLScriptBuilder - 解析动态SQL
6. MapperBuilderAssistant-工具类[辅助XMLMapperBuilder解析mapper.xml 完善属性信息]

parser.parse()
        解析mybatis-config.xml
                mapperElement - 获取Configuration
                        mapperParser.parse() - 解析Mapper映射文件 



    // --XMLConfigBuilder类--// 默认构造器
    public XMLConfigBuilder(InputStream inputStream, String environment,
                            Properties props) {
// XMLMapperEntityResolver类用于完成配置文件的校验,根据对应的DTD文件来实现// 1.new XPathParser() >>
// 2.this() 转调构造器重载 >>
        this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()),
                environment, props);
    }

    // --XPathParser类--
// 【完成配置文件的校验、相关属性的初始化操作、创建XPathFactory对象】
    public XPathParser(InputStream inputStream, boolean validation,
                       Properties variables, EntityResolver entityResolver) {
// 完成相关属性的初始化操作
        commonConstructor(validation, variables, entityResolver);// 创建Document对象 本质上是通过DOM来解析的,整个配置文件都会加载到内存中
        this.document = createDocument(new InputSource(inputStream));
    }

    // --XMLConfigBuilder类--
// 【初始化Configuration、对应属性设置、设定是否解析标记】
    private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
        super(new Configuration()); // 完成了Configuration的初始化
        ErrorContext.instance().resource("SQL Mapper Configuration");
        this.configuration.setVariables(props); // 设置对应的Properties属性
        this.parsed = false; // 设置 是否解析的标志为 false
        this.environment = environment; // 初始化environment
        this.parser = parser; // 初始化 解析器}
// --Configuration--// 可观察 new Configuration() >>
    public Configuration() {
// 为类型注册别名
            typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
            typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
// ...
        }
// --XMLConfigBuilder类--public Configuration parse() {
        if (parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }
        parsed = true;// evalNode方法,读取根节点 XPathParser,dom 和 SAX 都有用到 >>
        parseConfiguration(parser.evalNode("/configuration"));
        return configuration;
    }

    // 进入parseConfiguration方法 >>
    private void parseConfiguration(XNode root) {
        try {
// 对于全局配置文件各种标签的解析
            propertiesElement(root.evalNode("properties"));// 解析 settings 标签
            Properties settings = settingsAsProperties(root.evalNode("settings"));// 读取文件
            loadCustomVfs(settings);// 日志设置
            loadCustomLogImpl(settings);// 类型别名
            typeAliasesElement(root.evalNode("typeAliases"));// 插件
            pluginElement(root.evalNode("plugins"));// 用于创建对象
            objectFactoryElement(root.evalNode("objectFactory"));// 用于对对象进行加工
            objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));// 反射工具箱
            reflectorFactoryElement(root.evalNode("reflectorFactory"));// settings 子标签赋值,默认值就是在这里提供的 >>
            settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
            // 创建了数据源 >>
            environmentsElement(root.evalNode("environments"));
            databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            typeHandlerElement(root.evalNode("typeHandlers"));// 解析引用的Mapper映射器
            mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
            throw new BuilderException("Error parsing SQL ... Cause: " + e, e);
        }
    }

    // --XMLConfigBuilder类--
    private void mapperElement(XNode parent) throws Exception {
        if (parent != null) {
// child [configuration - mappers - package|mapper]
            for (XNode child : parent.getChildren()) {
// 进入mapperParser.parse方法 >>
                mapperParser.parse();
            }
        }
    }

    // --XMLMapperBuilder类--
    public void parse() {
// 总体上做了两件事情:对于语句的注册 和 接口的注册
        if (!configuration.isResourceLoaded(resource)) {
// 1、具体增删改查标签的解析。
// 一个标签 创建一个MappedStatement与之对应 >>
            configurationElement(parser.evalNode("/mapper"));
            configuration.addLoadedResource(resource);// 2、把namespace(接口类型)和工厂类绑定起来,放到一个map
// 一个namespace 一个 MapperProxyFactory >>
            bindMapperForNamespace();
        }
        parsePendingResultMaps();
        parsePendingCacheRefs();
        parsePendingStatements();
    }

    // --XMLMapperBuilder类--
    private void configurationElement(XNode context) {
        try {
            String namespace = context.getStringAttribute("namespace");
            if (namespace == null || namespace.equals("")) {
                throw new BuilderException("Mapper's namespace cannot be empty");
            }
            builderAssistant.setCurrentNamespace(namespace);// 添加缓存对象
            cacheRefElement(context.evalNode("cache-ref"));// 解析 cache 属性,添加缓存对象
            cacheElement(context.evalNode("cache"));// 创建 ParameterMapping 对象

            parameterMapElement(context.evalNodes("/mapper/parameterMap"));// 创建 List<ResultMapping>
            resultMapElements(context.evalNodes("/mapper/resultMap"));// 解析可以复用的SQL
            sqlElement(context.evalNodes("/mapper/sql"));// 解析增删改查标签,得到 MappedStatement >>
            buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
        } catch (Exception e) {
            throw new BuilderException("Error...'" + resource + "'. Cause: " + e, e);
        }
    }

    // 在buildStatementFromContext()方法中,创建了用来解析增删改查标签的XMLStatementBuilder,并且把创建 的MappedStatement添加到mappedStatements中
    private void buildStatementFromContext(List<XNode> list) {
        if (configuration.getDatabaseId() != null) {
            buildStatementFromContext(list, configuration.getDatabaseId());
        }
// 解析 Statement >>
        buildStatementFromContext(list, null);
    }

    // 进入重载方法
    private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
        for (XNode context : list) {
// 用来解析增删改查标签的 XMLStatementBuilderfinal XMLStatementBuilder statementParser =
            new XMLStatementBuilder(configuration, builderAssistant,
                    context, requiredDatabaseId);
            try {
// 解析 Statement,添加 MappedStatement 对象 >>
                statementParser.parseStatementNode();
            } catch (IncompleteElementException e) {
                configuration.addIncompleteStatement(statementParser);
            }
        }
    }

    // 进入statementParser.parseStatementNode()方法
// --XMLStatementBuilder类--
    public void parseStatementNode() {
        String id = context.getStringAttribute("id");
        String databaseId = context.getStringAttribute("databaseId");
// ...
// >> 关键的一步: MappedStatement 的创建 >>
        builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
    }
// 进入addMappedStatement()方法

    // --MapperBuilderAssistant--
    public MappedStatement addMappedStatement(String id,
//...
                                              String resultSets) {
// 创建 MappedStatement 对象
        MappedStatement对象 statement = statementBuilder.build();// 最关键的一步,在 Configuration 添加了 MappedStatement >>
        configuration.addMappedStatement(statement);
        return statement;
    }

    // 进入addMappedStatement()方法 观察
// --Configuration类--
    public void addMappedStatement(MappedStatement ms) {
        mappedStatements.put(ms.getId(), ms);// 观察mappedStatements对象
// protected final Map<String, MappedStatement> mappedStatements = new
        StrictMap<MappedStatement>
    }

    // --XMLMapperBuilder类--
    private void bindMapperForNamespace() {
        String namespace = builderAssistant.getCurrentNamespace();
        if (namespace != null) {
            Class<?> boundType = null;
            try {
// 根据名称空间加载对应的接口类型
                boundType = Resources.classForName(namespace);
            } catch (ClassNotFoundException e) {
            }
            if (boundType != null) {
// 判断 在MapperRegistry中是否注册的有当前类型的 MapperProxyFactory对象
                if (!configuration.hasMapper(boundType)) {
                    configuration.addLoadedResource("namespace:" + namespace);// 添加到 MapperRegistry,本质是一个 map,里面也有 Configuration >>
                    configuration.addMapper(boundType);
                }
            }
        }
    }

    // --Configuration类--
    public <T> void addMapper(Class<T> type) {
        mapperRegistry.addMapper(type);
    }

    public <T> void addMapper(Class<T> type) {
        if (type.isInterface()) { // 检测 type 是否为接口
            if (hasMapper(type)) { // 检测是否已经加装过该接口
                throw new BindingException("Type " + type + "...");
            }
            boolean loadCompleted = false;
            try {
// !Map<Class<?>, MapperProxyFactory<?>> 存放的是接口类型,和对应的工厂类的关系
                knownMappers.put(type, new MapperProxyFactory<>(type));// 注册了接口之后,根据接口,开始解析所有方法上的注解,例如 @Select >>
                MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);// 进入parse()方法 >>
                parser.parse();
                loadCompleted = true;
            } finally {
                if (!loadCompleted) {
                    knownMappers.remove(type);
                }
            }
        }
    }

    // 进入parse()方法
// --MapperAnnotationBuilder类--
    public void parse() {
        String resource = type.toString();
        if (!configuration.isResourceLoaded(resource)) {
// 先判断 Mapper.xml 有没有解析,没有的话先解析 Mapper.xml(例如定义 package 方式)
            loadXmlResource();
            configuration.addLoadedResource(resource);
            assistant.setCurrentNamespace(type.getName());// 处理 @CacheNamespace
            parseCache();// 处理 @CacheNamespaceRef
            parseCacheRef();// 获取所有方法
            Method[] methods = type.getMethods();
            for (Method method : methods) {
                try {
                    if (!method.isBridge()) {
// 该方法主要是解析对应类方法上的update、insert、delete、select等注解
// 添加到 MappedStatement 集合中 >>
                        parseStatement(method);
                    }
                } catch (IncompleteElementException e) {
                    configuration.addIncompleteMethod(new MethodResolver(this, method));
                }
            }
        }
// 处理解析异常的SQL节点parsePendingMethods();
    }

 

创建SqlSession会话对象

   // --测试类--SqlSession sqlSession = factory.openSession();
// --DefaultSqlSessionFactory--// DefaultSqlSessionFactory提供获得Session的多个方法,这些方法可以根据需要设定Session的SQL执行器的类
//型、事务类型和是否自动提交
    public SqlSession openSession() {
// DefaultSqlSessionFactory >>
        return openSessionFromDataSource(configuration.getDefaultExecutorType(),
                null, false);
    }
// --DefaultSqlSessionFactory--

    /**
     * 以上方法最终都执行本方法,设定SQL执行器的类型、事务隔离等级以及是否自动提交的设置
     *
     * @param execType   执行器类型
     * @param level      事务隔离级别
     * @param autoCommit 自动提交
     * @return
     */
    private SqlSession openSessionFromDataSource(ExecutorType execType,
                                                 TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
            final Environment environment = configuration.getEnvironment();// 获取事务工厂 >>
            final TransactionFactory transactionFactory =
                    getTransactionFactoryFromEnvironment(environment);
// 创建事务
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 根据事务工厂和默认的执行器类型,创建执行器 >>
            final Executor executor = configuration.newExecutor(tx, execType);// mybatis根据这些方法提供不同设置的 DefaultSqlSession 实例
            return new DefaultSqlSession(configuration, executor, autoCommit);
        } catch (Exception e) {
            closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }

    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 {
// 默认 SimpleExecutor
            executor = new SimpleExecutor(this, transaction);
        }
// 二级缓存开关,settings 中的 cacheEnabled 默认是 trueif (cacheEnabled) {
        executor = new CachingExecutor(executor);
    }
// 植入插件的逻辑,至此,四大对象已经全部拦截完毕
        executor=(Executor)interceptorChain.pluginAll(executor);
                return executor;
                }

 

创建过程中,发现,最后拿到了一个DefaultSqlSession;
DefaultSqlSession中存在:configuration对象、Executor对象;

Executor对象时SQL的真实执行者。

创建XxxMapper[代理]对象

创建Mapper对象的过程,实质上时获取了一个JDK动态代理对象的过程;
这个代理类会继承Proxy类,实现被代理的接口,其持有一个实现了InvocationHandler接口的MapperProxy类型的触发管理类。


    // --测试类--
// 4.通过SqlSession中提供的 API方法来操作数据库 >>
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    // --SqlSession接口--<T> T getMapper(Class<T> type);
// --DefaultSqlSession类--
    public <T> T getMapper(Class<T> type) {
        return configuration.getMapper(type, this);
    }

    // --Configuration类--
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// mapperRegistry中注册的有Mapper的相关信息 在解析映射文件时 调用过addMapper方法// 从mapperRegistry中获取对象 >>
        return mapperRegistry.getMapper(type, sqlSession);
    }

    // --MapperRegistry类--
// 获取Mapper接口对应的代理对象
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 从knownMappers中 获取Mapper接口对应的 MapperProxyFactory 对象// knownMappers的内容在何时存入?
// XMLConfigBuilder的mapperElement()方法 package分支处final MapperProxyFactory<T> mapperProxyFactory =
        (MapperProxyFactory<T>) knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known ...");
        }
        try {
// 进入newInstance()方法 >>
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
            throw new BindingException("Error getting mapper instance. Cause: " + e, e);
        }
    }

    // --MapperProxyFactory类--public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>
            (sqlSession, mapperInterface, methodCache);
// newInstance() >>
        return newInstance(mapperProxy);
                }
// 创建实现了 mapperInterface 接口的代理对象
protected T newInstance(MapperProxy<T> mapperProxy){
// 返回代理对象
// 1.类加载器;2.被代理类实现的接口;3.实现了 InvocationHandler 的触发管理类return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),
        new Class[]{mapperInterface},mapperProxy);
        }

 

执行SQL操作 [复杂一丢丢]

  // --测试类--// 调用接口方法
    List<User> list = mapper.selectUserList();

    // --MapperProxy类--
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
// toString hashCode equals getClass等方法,无需走到执行SQL的流程if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }else{
// 提升获取 mapperMethod 的效率,到 MapperMethodInvoker(内部接口) 的 invoke
// 普通方法会走到 PlainMethodInvoker(内部类) 的 invoke >>
            return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
        }
    }catch(Throwable t){
        throw ExceptionUtil.unwrapThrowable(t);
        }
        }

interface MapperMethodInvoker {
    // 进入到 MapperProxy 接口实现类 PlainMethodInvoker 的 invoke() 方法 >>
    Object invoke(Object proxy, Method method, Object[] args,
                  SqlSession sqlSession) throws Throwable;
}

private static class PlainMethodInvoker implements MapperMethodInvoker {
    private final MapperMethod mapperMethod;

    public PlainMethodInvoker(MapperMethod mapperMethod) {
    }

    public Object invoke(Object proxy, Method method, Object[] args,
                         SqlSession sqlSession) throws Throwable {
// 调用 execute 方法执行 SQL [SQL执行的真正起点] >>return mapperMethod.execute(sqlSession, args);
    }

}

    // --MapperMethod类--
// execute() 方法中 会根据不同的数据操作type 做不同的方法调用
    public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;// 根据 SQL 类型 执行相应的数据库操作 调用SqlSession对应的方法
        switch (command.getType()) {
            case INSERT: {
// convertArgsToSqlCommandParam() 将 方法参数 转换为 SQL的参数
// 通过 ParamNameResolver 处理args[] 数组 将用户传入的实参和指定参数名称关联起来
                Object param = method.convertArgsToSqlCommandParam(args);// sqlSession.insert() 调用SqlSession的insert方法
// rowCountResult 方法会根据 method 字段中记录的方法的返回值类型对结果进行转换result = rowCountResult(sqlSession.insert(command.getName(), param));break;
            }
            case UPDATE: {
            }
            case DELETE: {
            }
            case SELECT:
                if (method.returnsVoid() && method.hasResultHandler()) {
// 返回值为空 且 ResultSet通过 ResultHandler处理的方法
                    executeWithResultHandler(sqlSession, args);
                    result = null;
                }
// ...
                else {
// 返回值为 单一对象的方法
                    Object param = method.convertArgsToSqlCommandParam(args);// 普通 select 语句的执行入口
// 分析 selectOne() 方法 它会涉及到其他方法的调用 流程比较全面result = sqlSession.selectOne(command.getName(), param);
                }
        }
        return result;
    }

    // --SqlSession接口--<T> T selectOne(String statement, Object parameter);
// --DefaultSqlSession类--
// 来到了对外的接口的默认实现类DefaultSqlSession,selectOne()最终也是调用了selectList()方法
    public <T> T selectOne(String statement, Object parameter) {
// 来到了 DefaultSqlSession >>
        List<T> list = this.selectList(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected ... : " + list.size());
        } else {
            return null;
        }
    }

    public <E> List<E> selectList(String statement, Object parameter) {
// 为了提供多种重载(简化方法使用),和默认值
// 让参数少的调用参数多的方法,只实现一次 >>
        return this.selectList(statement, parameter, RowBounds.DEFAULT);
    }

    // 来到最终的执行方法
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        try {
// 根据command name(Statement ID)从Configuration中拿到MappedStatement// ms 中有xml中增删改查标签配置的所有属性,包括:
// id、statementType、sqlSource、useCache、入参、出参等
            MappedStatement ms = configuration.getMappedStatement(statement);// 如果 cacheEnabled = true(默认),Executor会被 CachingExecutor装饰
// 执行 Executor [CachingExecutor] 的 query() 方法 >>
            return executor.query(ms, wrapCollection(parameter), rowBounds,
                    Executor.NO_RESULT_HANDLER);
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }

    // --CachingExecutor类--
    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
                             ResultHandler resultHandler) throws SQLException {
// 获取SQL
        BoundSql boundSql = ms.getBoundSql(parameterObject);// createCacheKey() 方法创建了CacheKey >>
        CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);// CacheKey生成之后 query()方法重载 >>>>
        return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

    /**
     * 在计算 CacheKey 的过程中,有很多影响因子参与了计算。
     * 比如 MappedStatement 的 id 字段、SQL 语句、分页参数、运行时变量、Environment 的 id 字段等。
     * 通过让这些影响因子参与计算,可以很好的区分不同查询请求,
     * 所以,我们可以简单的把 CacheKey 看做是一个查询请求的 id。有了 CacheKey,就可以使用它读写缓存了。* 什么样的SQL是同一条SQL?
     * 看下方代码,
     * 也就是说,方法相同、翻页偏移相同、SQL相同、参数值相同、数据源环境相同,才会被认为是同一个查询。
     */
// --BaseExecutor类--
    public CacheKey createCacheKey() {
        cacheKey.update(ms.getId()); // 方法相同[com.gupaoedu.mapper.BlogMapper.selectBlogById]
        cacheKey.update(rowBounds.getOffset()); // 翻页偏移相同
        cacheKey.update(rowBounds.getLimit()); // 2147483647 = 2^31-1
        cacheKey.update(boundSql.getSql()); // SQL相同
        cacheKey.update(value); // 参数值相同
        cacheKey.update(configuration.getEnvironment().getId()) // 数据源环境相同
    }

    // --CachingExecutor类--// 查二级缓存
    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
                             ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        Cache cache = ms.getCache();// cache 对象是在哪里创建的? XMLMapperBuilder类
        xmlconfigurationElement()
// 由 <cache> 标签决定
        if (cache != null) {
// flushCache="true" 清空一级二级缓存 >>
            flushCacheIfRequired(ms);
            if (ms.isUseCache() && resultHandler == null) {
                ensureNoOutParams(ms, boundSql);// 获取二级缓存
// 缓存通过 TransactionalCacheManager、TransactionalCache 管理@SuppressWarnings("unchecked")
                List<E> list = (List<E>) tcm.getObject(cache, key);
                if (list == null) {
// 若二级缓存未命中,则进入BaseExecutor,向一级缓存或者数据库进行查询 >>
// 调用 BaseExecutor 类 的query()方法 >>>>
                    list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
// 写入二级缓存
                    tcm.putObject(cache, key, list);
                }
                return list;
            }
        }
// 走到 SimpleExecutor | ReuseExecutor | BatchExecutor
        return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

    // --BaseExecutor类--// CachingExecutor - delegate.query() >> BaseExecutor - query()// 查一级缓存
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,
                             ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
// 异常体系之 ErrorContext
        ErrorContext.instance().resource(ms.getResource()).activity("executing a
                query").object(ms.getId());
        if (closed) {
            throw new ExecutorException("Executor was closed.");
        }
        if (queryStack == 0 && ms.isFlushCacheRequired()) {
// flushCache="true"时,即使是查询,也清空一级缓存
            clearLocalCache();
        }
        List<E> list;
        try {
// 防止递归查询重复处理缓存
            queryStack++;// 查询一级缓存
// ResultHandler 和 ResultSetHandler的区别
            list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
            if (list != null) {
                handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
            } else {
// 来到真正的查询流程 queryFromDatabase() >>
                list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
            }
        } finally {
            queryStack--;
        }
        if (queryStack == 0) {
            for (DeferredLoad deferredLoad : deferredLoads) {
                deferredLoad.load();
            }
            deferredLoads.clear();
            if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                clearLocalCache();
            }
        }
        return list;
    }

    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter,
                                          RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;// 向缓存中存储一个占位符
        localCache.putObject(key, EXECUTION_PLACEHOLDER);
        try {
// 三种 Executor 的区别,看doUpdate
// 默认SimpleExecutor实现 >>
            list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
// 移除占位符
            localCache.removeObject(key);
        }
// 存储缓存查询结果 [写入一级缓存]
        localCache.putObject(key, list);// 存储过程相关逻辑 略过
        if (ms.getStatementType() == StatementType.CALLABLE) {
            localOutputParameterCache.putObject(key, parameter);
        }
        return list;
    }

    // --SimpleExecutor类--/
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
                               ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;
// StatementHandler -> Statement
        try {
            Configuration configuration = ms.getConfiguration();// 注意,已经来到SQL处理的关键对象 StatementHandler >>
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 获取一个 Statement对象 >>>>
            stmt = prepareStatement(handler, ms.getStatementLog());// 执行查询 >>>>>>
            return handler.query(stmt, resultHandler);
        } finally {
// 用完就关闭
            closeStatement(stmt);
        }
    }

    /
// --Configuration类--
// 在newStatementHandler()中,new了一个StatementHandler,先得到RoutingStatementHandler
    public StatementHandler newStatementHandler(Executor executor,
                                                MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// new RoutingStatementHandler() >>
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 植入插件逻辑(返回代理对象) [下次课讲]
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
    }

    // RoutingStatementHandler 就是一个功能路由 里面没有任何的实现,是用来创建基本的StatementHandler的。这里会根据MappedStatement里面的statementType决定StatementHandler的类型。
// 默认是PREPARED [STATEMENT、PREPARED、CALLABLE]
// --RoutingStatementHandler类--
    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// StatementType 是怎么来的? 增删改查标签中的 statementType="PREPARED",默认值 PREPAREDs
        witch(ms.getStatementType()) {
            case STATEMENT:
                delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            case PREPARED:
// 创建 StatementHandler 的时候做了什么? >>
                delegate = new PreparedStatementHandler(
                        executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            case CALLABLE:
                delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            default:
                throw new ExecutorException("Unknown ... : " + ms.getStatementType());
        }
    }
// --PreparedStatementHandler类--

    public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
    }

    // --BaseStatementHandler类--
    protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, ObjectparameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        this.configuration = mappedStatement.getConfiguration();
        this.executor = executor;
        this.mappedStatement = mappedStatement;
        this.rowBounds = rowBounds;
        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        this.objectFactory = configuration.getObjectFactory();
        if (boundSql == null) { // issue #435, get the key before calculating the statement
            generateKeys(parameterObject);
            boundSql = mappedStatement.getBoundSql(parameterObject);
        }
        this.boundSql = boundSql;
// 创建了四大对象的其它两大对象 >>
// 创建这两大对象的时候分别做了什么?
        this.parameterHandler = configuration.newParameterHandler(
                mappedStatement, parameterObject, boundSql);
        this.resultSetHandler = configuration.newResultSetHandler(executor,
                mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
    }

    // 四大对象都是可以被插件拦截的四大对象之一,所以在创建之后都要用拦截器进行包装的方法// 抬头一起看看与 newStatementHandler() 同在 Configuration 类中的其他几个方法// --Configuration类--
    public ParameterHandler newParameterHandler() {
    }

    public ResultSetHandler newResultSetHandler() {
    }

    public StatementHandler newExecutor() {
    }

    // 流程回到 SimpleExecutor 类的 doQuery() 方法
// prepareStatement() 方法 创建 Statement 对象
// --SimpleExecutor类--
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;// 获取 数据库连接 对象
        Connection connection = getConnection(statementLog);// 获取 Statement 对象 [BaseStatementHandler]
        stmt = handler.prepare(connection, transaction.getTimeout());// 为 Statement 设置 IN参数
        handler.parameterize(stmt);
        return stmt;
    }

    // 流程回到 SimpleExecutor 类的 doQuery() 方法
// query() 方法 执行查询操作 进入PreparedStatementHandler >>
// --PreparedStatementHandler类--
    public <E> List<E> query(Statement statement, ResultHandler resultHandler)
            throws SQLException {
// 调用 JDBC PreparedStatement API 执行操作
// 使用结果处理器对结果集进行处理
        PreparedStatement ps = (PreparedStatement) statement;// 执行 SQL [到了JDBC流程] >>
        ps.execute();// 处理结果集
        return resultSetHandler.handleResultSets(ps);
    }

 

;