第三章-Mybatis源码解析-以xml方式走流程-mapper解析(四)

3.2.2.7 selectKey解析

回到 XMLStatementBuilder.processSelectKeyNodes 的方法

java 复制代码
private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
    // 拿到所有 selectKey 节点
    List<XNode> selectKeyNodes = context.evalNodes("selectKey");
    if (configuration.getDatabaseId() != null) {
        parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
    }
    // 解析selectKey节点
    parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
    // 遍历并移除selectKey节点,防止干扰<insert>主节点后续解析流程
    removeSelectKeyNodes(selectKeyNodes);
}

/** 
parentId 就是上级节点id,其实就是<insert id={parentId}>标签的id;
parameterTypeClass 也是<insert>标签上设置的参数类型
langDriver 就是 XMLLanguageDriver
skRequiredDatabaseId 一般情况下为 null
*/
private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
    for (XNode nodeToHandle : list) {
        // 给selectKey 语句生成一个以"!selectKey"结尾的id
        String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
        // databaseId, skRequiredDatabaseId 这两个值一般为null,实际生产也基本为null
        String databaseId = nodeToHandle.getStringAttribute("databaseId");

        if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
            // 两种情况会走到这里:1.如果configuration 中没有当前 id 的statement;2.如果有 statement,但是databaseId 为  null
            parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
        }
    }
}

private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
    // 下面这一段都是获取开发时对selectKey配置的几个属性,各属性的值前面也有介绍,或者自己去官网捞出来看
    String resultType = nodeToHandle.getStringAttribute("resultType");
    Class<?> resultTypeClass = resolveClass(resultType);
    StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
    String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
    boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));

    //defaults
    boolean useCache = false;
    boolean resultOrdered = false;
    KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
    Integer fetchSize = null;
    Integer timeout = null;
    boolean flushCache = false;
    String parameterMap = null;
    String resultMap = null;
    ResultSetType resultSetTypeEnum = null;
    // 创建 sqlSource,看章节`3.2.2.6`
    SqlSource sqlSource = .createSqlSource(configuration, nodeToHandle, parameterTypeClass);
    SqlCommandType sqlCommandType = SqlCommandType.SELECT;
    // 创建 MappedStatement 并添加到 configuration 中,看章节`3.2.2.6`
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
                                        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
                                        resultSetTypeEnum, flushCache, useCache, resultOrdered,
                                        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);

    id = builderAssistant.applyCurrentNamespace(id, false);
    // 再从 configuration 中把 刚创建的 MappedStatement 对象取出来
    MappedStatement keyStatement = configuration.getMappedStatement(id, false);
    // 生成 SelectKeyGenerator 并存放到 configuration 的相应 HashMap 中
    configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
}

private void removeSelectKeyNodes(List<XNode> selectKeyNodes) {
    for (XNode nodeToHandle : selectKeyNodes) {
        // 遍历并移除selectKey节点
        nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
    }
}

3.3 总结

现在可以回答本章刚开始的几个问题了。

1、谁来解析?

答:由 XMLMapperBuilder类来解析

2、用什么解析?

答:内部通过XPath来解析xml

3、解析成什么?

答:解析成 SqlSource

4、解析结果如何存放?

答:最终通过 MappedStatement 来包装,并存放在Configuration中

5、最终用途?

答:待执行器执行sql时使用

后续将通过抖音视频/直播的形式分享技术,由于前期要做一些准备和规划,预计2024年6月开始,欢迎关注,如有需要或问题咨询,也可直接抖音沟通交流。

相关推荐
某空_2 分钟前
【Android】线程池解析
java
q***116512 分钟前
总结:Spring Boot 之spring.factories
java·spring boot·spring
追风少年浪子彦26 分钟前
Spring Boot 使用自定义 JsonDeserializer 同时支持多种日期格式
java·spring boot·后端
牢七36 分钟前
Javan
java
我叫黑大帅1 小时前
六边形架构?小白也能秒懂的「抗造代码秘诀」
java·后端·架构
不穿格子的程序员1 小时前
Java基础篇——JDK新特性总结
java·虚拟线程·jdk新特性
一乐小哥1 小时前
Java8 党狂喜!这篇把 Java9 到 25 的实用新功能讲透了,新手也能直接抄
java
草莓熊Lotso1 小时前
Git 本地操作进阶:版本回退、撤销修改与文件删除全攻略
java·javascript·c++·人工智能·git·python·网络协议
Ka1Yan1 小时前
[数组] - LeetCode 704. 二分查找
java·开发语言·算法·leetcode·职场和发展
合作小小程序员小小店1 小时前
web网页开发,在线%餐饮点餐%系统,基于Idea,html,css,jQuery,java,ssm,mysql。
java·前端·数据库·html·intellij-idea·springboot