mybatis分析-IncompleteElementException: Could not find result map

2023-05-16

错误描述

Caused by: org.apache.ibatis.builder.IncompleteElementException: Could not find result map xxxxxxx

结论

  1. 因为资源加载顺序违反resultMap节点的继承顺序,导致一些resultMap没有解析
  2. 解决方式:单独重新配置,使其重新解析一次

错误分析

  1. 定位报错位置(由于公司代码不方便截图)
    1.1 通过报错堆栈发现是dao层调用时触发
    (1)mybatis通过代理执行逻辑(MapperProxy#invoke) 在这里插入图片描述
    (2)主要关注MapperMethod mapperMethod = cachedMapperMethod(method);
    在这里插入图片描述
    在这里插入图片描述
    (3)继续关注XMLStatementBuilder#parseStatementNode --> MapperBuilderAssistant#addMappedStatement方法
    在这里插入图片描述
    在这里插入图片描述
    (3) 最终定位到从config中没有获取到值,所以抛出异常
  2. 为什么config里没有值?是没有解析吗?
    2.1 config是什么?见下方红色标记
    在这里插入图片描述
    2.2 resultMap节点解析后是怎么放入config中的?
    在这里插入图片描述
    在这里插入图片描述
    2.3 当resultMap节点中包含extend属性,但是在config中没有,则抛出异常(最终忽略),将未解析成功resultMapResolver添加config的incompleteResultMaps属性中
    在这里插入图片描述
    2.4 每解析完一个xml文件后,都会将之前未解析成功再次尝试解析
    在这里插入图片描述
    在这里插入图片描述
    2.5 综上所述,有可能extend加载顺序的问题导致有些resultMap节点没有解析成功
    (1)譬如 xxVo 继承 xxPo 继承 xxEnt,而恰好也是最后几个被解析的文件
  3. 为什么IDEA启动成功,但jar方式启动报错?
    3.1 怎么对比其中的差异性?
    (1)在Jar包启动时加入参数:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
    (2)IDEA以远程debug方式启动 在这里插入图片描述
    3.2 通过对比发现,IDEA以本地文件方式加载,而jar包读取Jar方式加载,读取协议不一样
    在这里插入图片描述
    (1)获取指定表达式的资源根路径(2个jar包或者2个模块)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    (2)两种启动方式对应两种协议
    在这里插入图片描述
    3.2 通过debug代码发现jar包加载没有按照包的层级加载导致了问题

补充

由于对jar包方式加载资源感兴趣,单独拉出来代码

public class JarResoureLoaderTest {

    @Test
    public void test() throws IOException {
        String mapperLocation = "classpath*:com/coe/cdcs/**/xml/**/*.xml";
        String rootDirPath = "classpath*:com/coe/cdcs/";
        String subPattern = "**/xml/**/*.xml";


        String path = "com/coe/cdcs/";
        Resource[] rootDirResources = getResources(path);
        Set<Resource> result = new LinkedHashSet<>(16);
        for (Resource rootDirResource : rootDirResources) {
            URL rootDirUrl = rootDirResource.getURL();
            if(ResourceUtils.isJarURL(rootDirUrl)){
                result.addAll(doFindPathMatchingJarResources(rootDirResource,rootDirUrl,subPattern));
            }
        }

        Resource[] mappers = result.toArray(new Resource[0]);

    }
    private Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource,URL rootDirURL,String subPattern) throws IOException {
        URLConnection con = rootDirURL.openConnection();
        JarFile jarFile = null;
        String jarFileUrl;

        //com/coe/cdcs/
        String rootEntryPath = null;
        boolean closeJarFile = false;

        if (con instanceof JarURLConnection) {
            JarURLConnection jarCon = (JarURLConnection) con;
            ResourceUtils.useCachesIfNecessary(jarCon);
            jarFile = jarCon.getJarFile();
            jarFileUrl = jarCon.getJarFileURL().toExternalForm();
            JarEntry jarEntry = jarCon.getJarEntry();
            rootEntryPath = (jarEntry != null ? jarEntry.getName() : "");
            closeJarFile = !jarCon.getUseCaches();
        }

        /**
         * 1. jar:file:/C:/Users/zhangjie/Desktop/出口组异常纪录/cdcs-admin-0.0.2-SNAPSHOT.jar!/BOOT-INF/classes
         *   1.1 第一次entryPath 为 "com/"
         * 2. result添加顺序有误(重点)
         */
        try{
            Set<Resource> result = new LinkedHashSet<>(8);
            for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) {
                PathMatcher pathMatcher = new AntPathMatcher();

                JarEntry entry = entries.nextElement();
                String entryPath = entry.getName();
                if (entryPath.startsWith(rootEntryPath)) {
                    //相对路径
                    String relativePath = entryPath.substring(rootEntryPath.length());
                    //subPattern = **/xml/**/*.xml  -->判断相对路径是否符合正则
                    if(pathMatcher.match(subPattern,relativePath)){
                        result.add(rootDirResource.createRelative(relativePath));
                    }
                }
            }
            return result;
        }finally {
            if (closeJarFile) {
                jarFile.close();
            }
        }

    }

    private Resource[] getResources(String rootDirPath) throws IOException{
        // admin和core包都包含com/coe/cdcs/
        Set<Resource> result = new LinkedHashSet<>(16);

        ResourceLoader resourceLoader = new DefaultResourceLoader();
        ClassLoader cl = resourceLoader.getClassLoader();
        Enumeration<URL> resourceUrls = cl.getResources(rootDirPath);
        while(resourceUrls.hasMoreElements()){
            URL url = resourceUrls.nextElement();
            Resource resource = new UrlResource(url);
            result.add(resource);
        }

        Resource[] rootDirResources = result.toArray(new Resource[0]);
        return rootDirResources;
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mybatis分析-IncompleteElementException: Could not find result map 的相关文章

  • 匹配一行中的第 n 个单词

    在我使用的应用程序中 我无法选择比赛组 1 我可以使用的结果是正则表达式的完整匹配 但我需要第 5 个单词 jumps 作为匹配结果 而不是完整的匹配项 The Quick Brown Fox Jumps 4 The quick brown
  • Mac“find”和Linux“find”之间的区别[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我继承了一个脚本作为应用程序构建过程的一部分 当我在构建服务器 Ubuntu Precise 上运行它时 它运行良好 但是当我在我的 ma
  • 更有效地查找和压缩数百万个文件

    我的服务器上有一个作业在命令行提示符下运行了两天 find data name filepattern 2009 exec tar uf 2009 tar 它正在采取forever 然后还有一些 是的 目标目录中有数百万个文件 在经过良好哈
  • `find -exec` 中这个奇怪的语法是什么?

    最近我遇到了一个奇怪的 bash 脚本 它用于从内部调用自定义 bash 函数find exec 我开发了以下简单的脚本来演示我需要解释的功能 在下面的示例中 函数foo每个都会被调用find result foo echo export
  • MyBatis - jdbcTypeForNull Oracle

    我将 MyBatis 与 Oracle 11g R2 数据库结合使用 我正在使用 MyBatis 3 3 和 ojdbc6 12 1 0 2 我的问题是每当我尝试插入一个空对象时我都会得到以下信息 org springframework j
  • 查明文件是否已更改

    我想查明自上次启动 shell 脚本以来文件是否已被修改 也许可以通过创建布尔值或其他东西 也许可以将上次运行脚本的时间保存在一个文本文件中 下次启动脚本时它应该读取该文件 然后它应该找出哪些文件已更改 以便我可以检查是否有文件已使用以下内
  • Java MyBatis 存储过程调用带 OUT 参数

    第一个问题 我试图返回一个 OUT 参数 而不是带注释的结果集 首先 这可能吗 如果是的话 人们会怎样做呢 MyBatis 3 0 6 数据库 SQL Server 2008 以下是我在 UserDAO 中调用方法的语法示例 Select
  • 命令行查找、sed、exec

    我在一个文件夹 子文件夹中有一堆文件 我试图制作某种单行代码 以便偶尔快速复制 粘贴 内容如下 太长 无法粘贴到此处 http pastebin com 4aZCPbwT http pastebin com 4aZCPbwT 我尝试过以下命
  • cmake find_path/find_library 检查失败

    我在用着CMake 2 8 2 http www cmake org Wiki CMake 2 8 2 Docs版本 该项目使用大量外部文件和自定义库 无法通过 find package 获得 并且有一长串元素 如下所示 find path
  • Mybatis 3.0.5 嵌套集合映射示例

    我正在研究 MyBatis 3 0 5 的映射功能 运行嵌入式模式的数据库是H2 1 3 160 在用户手册的帮助下 我让简单的部分工作起来 但我很难绘制出Set使用一个HashMap作为后备存储 以下是自定义集合的 Java 代码 该集合
  • 在以破折号开头的目录中查找

    find将文件名开头的破折号解释为选项的开头 使用熟悉的 技巧不起作用 因为选项位于文件名之后 引用无效 并将第一个破折号替换为 也不行 通常鼓励用户在此类文件名之前添加 但是如果我不知道给定的路径是绝对路径还是相对路径 我该怎么办 编辑
  • 为什么我在mongodb中找不到_id的记录

    我试图通过 MongoID id 字段在 mongoDB 中查找记录 我找到了有关如何执行此操作的示例 但无法使其发挥作用 例子 recID 010101010101011 would be a valid mongodb id recID
  • Mongo:如何通过存储在子数组中的ObjectId查找?

    我有一个包含这样记录的集合 id ObjectId 50ae3bdb50b3d6f01400027a admins ObjectId 50ae3bdb50b3d6f014000279 ObjectId 50ae3bdb50b3d6f0140
  • 查找早于 FILE 的文件而不包含 FILE

    我有一个计划要使用find给我一个比某些 FILE 更旧的文件列表 然后使用xargs or exec 将文件移动到其他地方 搬东西不是问题 xargs mv trash工作正常 现在 如果我尝试使用 newer FILE then FIL
  • 浏览器Ctrl+F查找不可见文本

    Can the browser feature of Ctrl F to find text be integrated with text in popup windows I d like to have some scientific
  • Mybatis 期望 selectOne() 返回一个结果(或 null),但发现:190

    我正在尝试从数据库检索值 但无法获取所有值 我正进入 状态TooManyResultsException 映射器接口 这是我正在调用的映射器接口 public interface ITranslatorDAO Map
  • 将 pandas 数据框中的所有 inf、-inf 值替换为 NaN

    我有一个大型数据框 不同列中包含 inf inf 值 我想用 NaN 替换所有 inf inf 值 我可以逐栏这样做 所以这有效 df column name df column name replace np inf np nan 但我的
  • MyBatis 映射中的复合键

    我无法将组合键传递给 MyBatis
  • 使用 find 命令搜索直到第一个匹配项

    我只需要搜索可以在任何地方的特定目录有没有办法运行此命令直到第一个匹配 谢谢 我现在使用 find noleaf name experiment type d wc l 正如鲁道夫 米尔鲍尔 Rudolf M hlbauer 所提到的 qu
  • 使用正则表达式查找并替换(批处理.BAT)

    我想在多个文本文件中进行查找 替换 如何使用 BAT 实现自动化 我还需要正则表达式 示例 查找

随机推荐