草庐IT

Invalid bound statement (not found)

毛惜时 2023-07-19 原文

目录

一、遇到的问题

二、分析思路

1、映射文件

2、测试类

三、解决方案


一、遇到的问题

前几日,有个工作不久的同事找我帮他解决一个 Mybatis 的问题。他写了一个增删改查,但是在启动程序的时候报错:Invalid bound statement (not found) 。他试图解决该异常,花了一个小时还是没有解决,所以向我求助。所谓当局者迷,我帮他梳理了一下开发逻辑,几分钟后他发现了问题,并解决了该异常。刚工作两三年的开发者特别容易碰到该异常,但是只要理清思路,就很容解决问题。我将分析问题的思路记录一下,希望能帮到你。

二、分析思路

Mybatis 开发有两种方式,一种是原始 Dao 开发方式,另一种是 Mapper 动态代理开发方式。在开发项目时,我们会用 Mapper 动态代理开发方式,动态代理会自动帮我们生成 Mapper 的代理类,将细节封装起来。但是,在分析问题的时候,我们用原始 Dao 开发方式,可以让我们了解到 statement 绑定映射文件的细节。

下面使用原始 Dao 的开发方式演示一下 statement 是如何绑定映射文件中的 Sql 语句的。

1、映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.mapper.UserMapper">
        <!-- 查询所有的用户名 -->
    <select id="findUserNameList" resultType="java.lang.String">
        select user_name userName from user
    </select>
</mapper>

2、测试类

public class Test {

    //会话工厂
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void createSqlSessionFactory() throws IOException {
        // 配置文件
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder()
                .build(inputStream);

    }

    // 查询所有的用户名
    @Test
    public void testFindUserNameById() {
        // 数据库会话实例
        SqlSession sqlSession = null;
        try {
            // 创建数据库会话实例sqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 查询所有的用户名
            List<String> list = sqlSession.selectList("com.test.mapper.UserMapper.findUserNameById");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }

    }
}

在上面的测试中,使用了 sqlSession 的 selectList 方法,中间的参数就是 statement 。该参数用来确定映射文件中的 Sql 语句,换句话说就是用这个 statement 绑定映射文件中的 Sql 语句。

该参数是用映射文件中的 namespace 和 select 标签的 id 组合而成的,在项目是唯一的。示例中映射文件的 namespace 是:com.test.mapper.UserMapper,select 标签的 id 是:indUserNameById ,所以组合起来的 statement 是 com.test.mapper.UserMapper.findUserNameById

如果 statement 写错了,就会导致找不到映射文件中的 Sql 语句,就会报 Invalid bound statement (not found) 。所以造成该异常的原因是 statement 和 Sql 语句不匹配。

在实际项目会使用 Mapper 动态代理的开发方式,自动生成 mapper 接口的实现类,就更容易出现该异常了。

三、解决方案

既然知道了造成该异常的原因,就容易解决了,如果通过 statement 找不到映射文件中的 Sql 就会报错误:Invalid bound statement (not found) 。在项目中一般都是使用 Mapper 动态代理,所以我们要解决的也是动态代理的问题。先说一下 Mapper 动态代理的实现原理,看完之后你就知道应该怎么解决该异常了。

Mapper 动态代理只需要开发定义 Mapper 接口,Mybatis 会根据接口创建动态代理对象。使用该种方式开发,需要遵守一定的开发规范,规范如下 4 点:

  1. Mapper.xml 文件中的 namespace 与 mapper 接口的类路径相同。
  2. Mapper 接口方法名和 Mapper.xml 中定义的每个 statement 的 id 相同
  3. Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 Sql 的 parameterType 的类型相同
  4. Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 Sql 的 resultType 的类型相同 

所以,我们在使用 Mapper 动态代理遇到该异常,就是要检查是否遵守开发规范,因为粗心或单词写错了,容易导致程序报错。

我列了几个检查步骤,你跟着步骤检查一下,肯定能找到问题的所在之处。步骤如下 7 点:

  1. 检查 target 目录中有没有 Mybatis 的映射文件
  2. 检查 mybatis.mapper-locations 配置,该配置是把 mapper 的位置告诉 Mybatis 。默认是mapper-locations: classpath*:/mapper/**/*.xml
  3. 检查映射文件是不是放在 resources/mapper 目录中
  4. 检查映射文件中的 namespace 与 mapper 接口的类路径是不是一样
  5. 检查映射文件中的 statement 是不是和 Mapper 接口的方法名一样
  6. 检查映射文件中的 statement 的 parameterType 和 resultType 是不是和 Mapper 接口的方法中的入参和出参一样
  7. 如果你使用 Idea 开发,检查一下 resources 目录,在该目录下创建下级目录是不能一次性创建的,要创建完成一个目录后再创建另外的下级目录

另外,如果你遇到过该异常,并且遇到的错误不在上述之中。不妨在留言区提出,大家一起讨论一下,给后来者提个醒,避免遇到坑。

有关Invalid bound statement (not found)的更多相关文章

  1. ruby - 覆盖 Sinatra 默认的 NotFound 错误页面 - 2

    有没有办法覆盖sinatra默认的NotFound错误页面(“Sinatra不知道这个小事”)?我希望sinatra在找不到正确的路由时仅显示一个纯字符串作为“找不到方法”,但是当我从路由内部引发404错误时,我希望它显示传入的错误消息。像这样实现not_foundblock:not_founddo'Methodnotfound.'end有效,但它不是一个有效的选项,因为我希望能够从这样的路由中抛出我自己的NotFound错误消息:get'/'dobegin#someprocessingthatcanraiseanexceptionifresourcenotfoundrescue=>e

  2. go - httprouter 设置自定义 NotFound - 2

    我正在使用https://github.com/julienschmidt/httprouter在我的Go项目中。我刚才问了这个问题,@icza解决了这个问题:httprouterconfiguringNotFound但是现在,开始一个新项目并使用非常相似的代码时,我似乎在控制台中遇到了错误。尝试配置自定义处理程序NotFound和MethodNotAllowed我正在使用:router.NotFound=customNotFoundrouter.MethodNotAllowed=customMethodNotAllowed产生:cannotusecustomNotFound(type

  3. c# - IHttpActionResult 方法无法返回 NotFound() - 2

    我正在为我的网站开发WebAPI,但遇到了问题。目前,API应该返回指定用户的详细信息。这是我的帐户Controller:usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Web;usingSystem.Web.Mvc;usingSystem.Web.Http;usingSystem.Net;usingRoditRepoAPIV2.Models;namespaceRoditRepoAPIV2.Controllers{publicclassAccountController:Controlle

  4. java - AWS 错误消息 : InvalidInstanceID. NotFound - 2

    我正在尝试启动亚马逊EC2具有[startInstance][2]方法的云机器,使用Java中的aws-sdk。我的代码如下。publicStringstartInstance(StringinstanceId)throwsException{ListinstanceIds=newArrayList();instanceIds.add(instanceId);StartInstancesRequeststartRequest=newStartInstancesRequest(instanceIds);startRequest.setRequestCredentials(getCrede

  5. ios - Xcode 5 IOS 7 错误 : failed to launch '/private/var/mobile/Applications/' -- NotFound - 2

    我正在尝试在我的IOS设备上测试应用程序。我已经得到了一些工作,但是我现在尝试安装的那个(https://developer.apple.com/library/iOS/samplecode/AccelerometerGraph/Introduction/Intro.html)给我以下错误。我收到一个弹出窗口,上面写着:Couldnotlaunch“AccelerometerGraph”在控制台中:error:failedtolaunch'/private/var/mobile/Applications/45F20998-B62C-4D0F-B867-9DB4DF15D94B/Acce

  6. 编译报错 CMake Error: The following variables are used in this project, but they are set to NOTFOUND. - 2

    1.Problem用一块新的Nvidia的JetsonNX板编译时遇到一个报错,如下:CMakeError:Thefollowingvariablesareusedinthisproject,buttheyaresettoNOTFOUND.PleasesetthemormakesuretheyaresetandtestedcorrectlyintheCMakefiles:CUDA_cublas_device_LIBRARY(ADVANCED)linkedbytarget"fast_vgicp_cuda"indirectory/home/xi/run_ws/src/localization/fa

  7. java - 如何使用 JPA 解决 javax.persistence.EntityNotFoundException(不是使用 @NotFound) - 2

    我们正在使用JPA从数据库加载一些东西。一些实体之间可能有可选的关系,例如@EntitypublicclassFirst{....@OneToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH,CascadeType.DETACH})@JoinColumns(value={JoinColumn(name="A_ID",referencedColumnName="A_ID",insertable=false,updatable=false),JoinColumn(name="B_ID",refere

随机推荐