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 的相关文章

  • cmake find_path/find_library 检查失败

    我在用着CMake 2 8 2 http www cmake org Wiki CMake 2 8 2 Docs版本 该项目使用大量外部文件和自定义库 无法通过 find package 获得 并且有一长串元素 如下所示 find path
  • 下划线充当分隔符 C# RTF Box

    我正在开发一个 Winforms 应用程序 并使用 RichTextBox 控件上的 Find 来查找要设置样式的特定关键字 由于某种原因 尽管指定了 WholeWord 标志 Find 似乎仍将其中带有下划线的单词视为 2 个单独的单词
  • Objective-C 在 NSArray 中搜索字符串?

    我有一个字符串数组 我如何才能找出字符串在数组中的索引 NSArray indexOfObject http developer apple com mac library documentation Cocoa Reference Fou
  • 错误:“grep:参数列表太长”[重复]

    这个问题在这里已经有答案了 我正在尝试运行以下命令 但出现参数太长错误 你能帮我吗 HOST grep rl pattern home public html bash bin grep Argument list too long 有没有
  • 如何告诉 find 命令转义文件名中的空格字符?

    我有一个单行 find 命令 它递归地检查并打印出在特定时间范围内创建的特定文件类型的大小 所有者和名称 但在结果中 给出文件名列 直到目录或文件名中的第一个空格字符为止 有没有办法在这个单一命令中解决这个问题 而无需在 bash 中编写任
  • Mongo:如何通过存储在子数组中的ObjectId查找?

    我有一个包含这样记录的集合 id ObjectId 50ae3bdb50b3d6f01400027a admins ObjectId 50ae3bdb50b3d6f014000279 ObjectId 50ae3bdb50b3d6f0140
  • “查找”或任何其他工具可以广度优先搜索文件吗?

    有时我知道某个文件并不那么深 但是非常密集的子目录不允许我轻松找到我想要的文件 Can find http www gnu org software findutils manual html mono find html 或任何其他工具
  • Mybatis 期望 selectOne() 返回一个结果(或 null),但发现:190

    我正在尝试从数据库检索值 但无法获取所有值 我正进入 状态TooManyResultsException 映射器接口 这是我正在调用的映射器接口 public interface ITranslatorDAO Map
  • python 课堂上有太多自我

    我正在学习 Python OOP 并尝试将 Java 类转换为 Python 类 请参阅此 PDF 中的第 15 页了解 Java 代码 google 文档link https docs google com open id 1eqzajO
  • 如何使用unix“find”命令查找所有cpp和h文件?

    我知道要找到所有 h我需要使用的文件 find name h 但如何找到所有 h AND cpp files find name h print o name cpp print or find name h o name cpp prin
  • Perl 初学者:如何查找/替换文件中的 ASCII 字符?

    我对 Perl 完全陌生 我认为这将是解决我的简单任务的最佳语言 我需要将二进制文件转换为可读的文件 并且需要查找和替换字符串 例如 x00 x39 into x09 选项卡 或类似的东西 从 bash 开始 我从以下内容开始 效果很好 p
  • str.find 怎么这么快?

    我之前遇到过一个问题 我在迭代字符串并使用切片时寻找子字符串 原来这是一个really关于性能的坏主意 str find速度要快得多 但我不明白为什么 import random import string import timeit Ge
  • 查找 div 元素中的所有链接并禁用它们

    假设我有一些如下所示的 HTML 元素 div span a href some link Click me a span div Hello everybody Click a href some link else me a to do
  • 在 Unix 上查找不以特定扩展名结尾的文件名?

    有没有一种简单的方法可以递归地查找目录层次结构中的所有文件not以扩展名列表结尾 例如 所有非 dll 或 exe 的文件 UNIX GNU find 虽然功能强大 但似乎没有exclude模式 或者我错过了 而且我总是发现很难使用正则表达
  • 在 Dart 中查找和替换字符串

    我正在为这个应用程序使用 flutter 但我在应用程序的逻辑方面遇到了问题 任何帮助深表感谢 应用程序目标 通过以下方式将所有输入缩写解码 替换 为单词 用户通过文本框输入文本 应用程序查找任何缩写 几个 并仅用文本替换缩写 我能够使用一
  • 如何在unix中移动或复制“find”命令列出的文件?

    我有使用下面的命令看到的某些文件的列表 但是如何将列出的这些文件复制到另一个文件夹 例如 test 中 find mtime 1 exec du hc 添加到 Eric Jablow 的答案中 这是一个可能的解决方案 它对我有用 linux
  • 如何按文件大小对查找结果进行排序

    如何按文件大小对 find 命令的结果进行排序 我试图对这个 find 命令的结果进行排序 find src type f print0 我不需要目录的大小 我需要仅按大小排序的文件相对路径 这是如何做的using find command
  • 使用空的weak_ptr作为参数调用map::count安全吗?

    打电话安全吗map count http www cplusplus com reference map map count on an 未初始化因此为空weak ptr http en cppreference com w cpp mem
  • 如何用spring启动myBatis实现?

    我想与 myBatis 合作 我已阅读 MyBatis 3 用户指南 现在我正在努力实施它 最近我学习了spring 所以我很难实施 所以我需要一些有用的资源来逐步实现它 首先将 MyBatis Spring jar 添加到类路径中 从您的
  • jQuery 提取 div 内的文本,但不在 p 标签中

    在下面的代码中 我想将一个变量放入文本中div但不是里面的东西p tag div class review content merchant review content I want to grab this text p class r

随机推荐