mybatis-plus通用mapper调用报错:Invalid bound statement

本文解决在SpringBoot项目中整合Mybatis-Plus后,调用BaseMapper自带方法报错的问题,通过替换sqlSessionFactory并添加MybatisPlusConfig配置类实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用springboot整合mybatis-plus后,调用自定义的方法正常,调用BaseMapper中自带的方法报错如下:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.rkang.enterprise.mapper.EmployeeInfoMapper.selectOne
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:227) ~[mybatis-3.4.6.jar:3.4.6]
    at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:49) ~[mybatis-3.4.6.jar:3.4.6]
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65) ~[mybatis-3.4.6.jar:3.4.6]
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58) ~[mybatis-3.4.6.jar:3.4.6]
    at com.sun.proxy.$Proxy70.selectOne(Unknown Source) ~[na:na]
    at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:259) ~[mybatis-plus-extension-3.1.1.jar:3.1.1]
    at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:192) ~[mybatis-plus-extension-3.1.1.jar:3.1.1]
    at com.baomidou.mybatisplus.extension.service.IService$$FastClassBySpringCGLIB$$f8525d18.invoke(<generated>) ~[mybatis-plus-extension-3.1.1.jar:3.1.1]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at cn.rkang.enterprise.local.service.EmployeeInfoService$$EnhancerBySpringCGLIB$$7e12f21b.getOne(<generated>) ~[classes/:na]

跟进源码发现是methodProxy.invoke(target, argsToUse)报错,

if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    retVal = methodProxy.invoke(target, argsToUse);
} else {
    retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
}

在invoke方法组装sqlmand的时候,MappedStatement没有组装成功,始终是null

public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
    String methodName = method.getName();
    Class<?> declaringClass = method.getDeclaringClass();
    MappedStatement ms = this.resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration);
    if (ms == null) {
        if (method.getAnnotation(Flush.class) == null) {
            throw new BindingException("Invalid bound statement (not found): " + mapperInterface.getName() + "." + methodName);
        }

        this.name = null;
        this.type = SqlCommandType.FLUSH;
    } else {
        this.name = ms.getId();
        this.type = ms.getSqlCommandType();
        if (this.type == SqlCommandType.UNKNOWN) {
            throw new BindingException("Unknown execution method for: " + this.name);
        }
    }
}
解决方法:将mybatis的sqlSessionFactory替换成mybatis-plusd的MybatisSqlSessionFactoryBean,添加配置类MybatisPlusConfig 

package cn.rkang.enterprise.common.config;

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;

@Configuration
public class MybatisPlusConfig {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private MybatisProperties properties;

    @Autowired
    private ResourceLoader resourceLoader = new DefaultResourceLoader();

    @Autowired(required = false)
    private Interceptor[] interceptors;

    @Autowired(required = false)
    private DatabaseIdProvider databaseIdProvider;

    /**
     *   mybatis-plus分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor page = new PaginationInterceptor();
        page.setDialectType("mysql");
        return page;
    }
    /**
     * 这里全部使用mybatis-autoconfigure 已经自动加载的资源。不手动指定
     * 配置文件和mybatis-boot的配置文件同步
     * @return
     */
    @Bean
    public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean() {
        MybatisSqlSessionFactoryBean mybatisPlus = new MybatisSqlSessionFactoryBean();
        mybatisPlus.setDataSource(dataSource);
        mybatisPlus.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            mybatisPlus.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }
        if (!ObjectUtils.isEmpty(this.interceptors)) {
            mybatisPlus.setPlugins(this.interceptors);
        }
        MybatisConfiguration mc = new MybatisConfiguration();
        mc.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
        //数据库字段设计为驼峰命名,默认开启的驼峰转下划线会报错字段找不到
        mc.setMapUnderscoreToCamelCase(false);
        mybatisPlus.setConfiguration(mc);
        if (this.databaseIdProvider != null) {
            mybatisPlus.setDatabaseIdProvider(this.databaseIdProvider);
        }
        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            mybatisPlus.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }
        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            mybatisPlus.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            mybatisPlus.setMapperLocations(this.properties.resolveMapperLocations());
        }
        return mybatisPlus;
    }

}
问题解决
<think>好的,用户在使用PowerMockito时遇到了一个错误:“can not find for thisentity[xxx. Xxx. sc01custinfo]”。我需要先理解这个错误的上下文。用户提供的代码片段是PowerMockito的when...thenReturn用法,试图模拟sc01custinfomapper的selectOne方法,传入any(lambdaquerymapper.class)参数,并返回sc01custinfo对象。 首先,错误信息提示找不到对应的实体类。这可能涉及到几个方面的问题。常见的原因包括类路径问题、包名错误、实体类未正确配置或者Mockito/PowerMockito的配置问题。 我需要逐步分析可能的原因。首先检查实体类是否存在,用户需要确认sc01custinfo类是否存在于项目中,并且包路径是否正确。有时候,拼写错误或者包路径不正确会导致类无法被找到,尤其是在使用ORM框架如MyBatis时,实体类需要正确的注解或配置。 其次,考虑MyBatis的映射配置。如果使用的是MyBatis,需要确认XML映射文件或接口中是否正确引用了sc01custinfo实体类。例如,在Mapper接口中,方法的返回类型是否正确声明为该实体类,或者在XML中是否有对应的resultMap配置。 接下来,检查Mockito的any()方法使用是否正确。any(Class<T> clazz)需要传入正确的参数类型。如果selectOne方法的参数类型是LambdaQueryMapper,那么any(LambdaQueryMapper.class)是正确的。但需要注意,LambdaQueryMapper是否与实际的Mapper接口匹配,是否存在泛型参数或其他继承关系的问题。 另外,Mockito的版本兼容性也可能导致问题。某些旧版本可能不支持Lambda表达式或特定的参数匹配方式,需要确认使用的Mockito和PowerMockito版本是否兼容,并查看是否有相关的已知问题或更新日志。 还有可能是在单元测试的配置中,没有正确初始化Mock。例如,使用@Mock注解的sc01custinfomapper是否已经被正确初始化,或者在测试方法中是否调用了MockitoAnnotations.initMocks(this)来初始化mock对象。 另外,考虑是否在测试类上正确使用了@RunWith注解,例如@RunWith(PowerMockRunner.class)或@RunWith(MockitoJUnitRunner.class),以确保mock对象被正确处理。 用户还可能遇到的问题是,在模拟selectOne方法时,返回的对象类型与Mapper接口中声明的返回类型不匹配。例如,如果selectOne方法应该返回sc01custinfo类型,但实际返回的是其他类型,或者返回的对象没有正确实例化,可能导致类型不匹配的错误。 此外,检查是否有混淆的导包情况,比如误导入了其他包中的同名类,导致编译器无法正确识别实体类。 总结下来,解决步骤可能包括: 1. 确认实体类存在且包路径正确。 2. 检查MyBatisMapper配置是否正确引用实体类。 3. 验证Mockito的any()方法参数是否正确。 4. 确保Mock对象正确初始化。 5. 检查测试运行器和版本兼容性。 6. 确认返回对象类型与声明一致。 用户可能需要逐一排查这些可能性,逐步定位问题所在。同时,查看完整的错误堆栈信息,可能会有更详细的线索,比如类加载失败的具体原因,或者哪个环节无法找到实体类。如果用户提供了具体的包名和错误堆栈,可以更精准地诊断问题。</think>在使用 PowerMockito 模拟 `selectOne` 方法时,报错 `can not find for thisentity[xxx.Xxx.sc01custinfo]`,通常是由以下原因导致的。以下是逐步排查和解决方案: --- ### **1. 确认实体类是否存在** - **问题**:`sc01custinfo` 实体类未定义或路径错误。 - **检查步骤**: - 确认项目中是否存在 `xxx.Xxx.sc01custinfo` 类(包路径是否正确)。 - 确保实体类已正确编译并包含在类路径中(如 Maven/Gradle 构建工具的依赖配置)。 --- ### **2. 检查 MyBatis 映射配置** 如果使用 MyBatisMyBatis-Plus- **问题**:Mapper 接口未正确绑定实体类。 - **解决步骤**: 1.Mapper 接口上检查泛型参数: ```java public interface SC01CustInfoMapper extends BaseMapper<SC01CustInfo> { ... } ``` 2. 如果使用 XML 映射文件,检查 `resultType` 或 `resultMap` 是否正确指向 `sc01custinfo`: ```xml <select id="selectOne" resultType="xxx.Xxx.SC01CustInfo"> ``` --- ### **3. 检查 Mockito 的 `any()` 方法使用** - **问题**:`any(LambdaQueryMapper.class)` 参数类型不匹配。 - **解决步骤**: 1. 确认 `selectOne` 方法的参数类型是否为 `LambdaQueryWrapper`(常见于 MyBatis-Plus)。 2. 修正 `any()` 的参数类型: ```java when(sc01CustInfoMapper.selectOne(any(LambdaQueryWrapper.class))) .thenReturn(sc01CustInfo); ``` --- ### **4. 确保 Mock 对象已初始化** - **问题**:未正确初始化 Mapper 的 Mock 对象。 - **解决步骤**: 1. 使用 `@Mock` 注解或手动初始化 Mock: ```java @Mock private SC01CustInfoMapper sc01CustInfoMapper; @Before public void setup() { MockitoAnnotations.initMocks(this); } ``` 2. 检查测试类是否添加了正确的 Runner(如 `PowerMockRunner`)。 --- ### **5. 检查返回对象类型** - **问题**:`thenReturn(sc01CustInfo)` 返回的对象类型与 Mapper 声明不匹配。 - **解决步骤**: - 确认 `sc01CustInfo` 是 `SC01CustInfo` 的实例: ```java SC01CustInfo sc01CustInfo = new SC01CustInfo(); ``` --- ### **6. 版本兼容性问题** - **问题**:Mockito/PowerMockito 版本与 MyBatis 或框架冲突。 - **解决步骤**: - 更新依赖到最新稳定版本,确保兼容性: ```xml <!-- Maven 示例 --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>5.3.1</version> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.9</version> </dependency> ``` --- ### **完整代码示例** ```java @RunWith(PowerMockRunner.class) @PrepareForTest({SC01CustInfoMapper.class}) public class YourTestClass { @Mock private SC01CustInfoMapper sc01CustInfoMapper; @Before public void setup() { MockitoAnnotations.initMocks(this); } @Test public void testSelectOne() { // 1. 创建实体对象 SC01CustInfo sc01CustInfo = new SC01CustInfo(); // 2. 模拟 selectOne 方法 when(sc01CustInfoMapper.selectOne(any(LambdaQueryWrapper.class))) .thenReturn(sc01CustInfo); // 3. 调用测试方法并断言 // ... } } ``` --- ### **常见错误总结** | 错误原因 | 解决方向 | |-------------------------|-----------------------------| | 实体类路径错误 | 检查包路径和编译结果 | | MyBatis 映射配置错误 | 检查 Mapper 接口和 XML 配置 | | `any()` 参数类型不匹配 | 使用 `any(LambdaQueryWrapper.class)` | | Mock 对象未初始化 | 添加 `@Mock` 和初始化代码 | | 返回对象类型不匹配 | 确保返回实例类型正确 | 如果问题仍未解决,请检查完整错误堆栈,确认具体是哪一行代码触发了 `can not find for thisentity`,并核对实体类的包路径和名称。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值