You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将MyBatis Mapper作为多模块通用仓库时出现绑定异常的问询

问题排查:MyBatis Invalid bound statement 异常

问题背景

我需要开发一个可在多模块中复用的通用模块,其中多数模块基于MyBatis,部分模块使用Spring Data + Hibernate。针对MyBatis场景的实现步骤如下:

  1. 定义通用仓库接口ScheduledTaskRepository
public interface ScheduledTaskRepository {
    List<ScheduledTask> getTasksByStateAndType(ScheduledTaskState state, ScheduledTaskType type, int maxRunCount);
    void create(ScheduledTask task);
    void update(ScheduledTask task);
    List<ScheduledTask> getTasksForReset(ScheduledTaskState state, ScheduledTaskType type, int runCount);
    void resetTask(long id);
    ScheduledTask get(long id);
}
  1. 编写MyBatis实现类MybatisScheduledTaskRepository,通过@Mapper和@ConditionalOnBean(MybatisAutoConfiguration.class)注解实现条件加载,并在重写方法上添加SQL注解
@Mapper
@ConditionalOnBean(MybatisAutoConfiguration.class)
public interface MybatisScheduledTaskRepository extends ScheduledTaskRepository {
    @Override
    @Select("SELECT * FROM scheduled_tasks WHERE state = #{state} AND type = #{type} AND run_count < #{maxRunCount}")
    List<ScheduledTask> getTasksByStateAndType(@Param("state") ScheduledTaskState state,
                                                @Param("type") ScheduledTaskType type,
                                                @Param("maxRunCount") int maxRunCount);
    // 其他重写方法省略...
}
  1. 在通用模块中创建ScheduledTaskService,依赖ScheduledTaskRepository接口实现业务逻辑
  2. 通用模块的build.gradle中引入MyBatis相关依赖,并配置spring.factories实现自动配置

将该通用模块作为依赖引入其他模块后,运行测试时调用Service抛出以下异常:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): ru.test.app.common.scheduling.repository.ScheduledTaskRepository.getTasksByStateAndType
// 异常栈信息省略...

排查方向及解决方法

1. 确认容器中注入的Repository实例类型

异常提示未找到**父接口ScheduledTaskRepository**的方法绑定,说明Service可能注入的是父接口的代理对象,而非MyBatis实现类MybatisScheduledTaskRepository。

  • 检查Service中的注入逻辑:如果是@Autowired ScheduledTaskRepository repository,Spring可能无法自动识别要注入MyBatis版本的实现。
  • 解决方式:
    • 给MybatisScheduledTaskRepository添加@Primary注解,确保当存在多个ScheduledTaskRepository实现时优先注入该实例;
    • 或者在Service中通过@Qualifier("mybatisScheduledTaskRepository")指定要注入的Bean名称。

2. 检查MyBatis的Mapper扫描范围

通用模块作为依赖Jar被引入时,MyBatis可能未扫描到MybatisScheduledTaskRepository这个Mapper接口。

  • 确认主应用模块是否配置了@MapperScan,并包含通用模块中Mapper所在的包路径(如ru.test.app.common.scheduling.repository);
  • 或者在通用模块中编写自动配置类,统一配置Mapper扫描:
    @Configuration
    @ConditionalOnBean(MybatisAutoConfiguration.class)
    @MapperScan(basePackages = "ru.test.app.common.scheduling.repository")
    public class MybatisScheduledTaskAutoConfiguration {
    }
    
    然后在通用模块的META-INF/spring.factories中注册该自动配置类:
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    ru.test.app.common.scheduling.config.MybatisScheduledTaskAutoConfiguration
    

3. 验证方法签名一致性

确保MybatisScheduledTaskRepository中重写的方法与父接口ScheduledTaskRepository的方法签名完全一致,包括参数类型、名称、返回值类型。

  • 注意父接口方法无@Param注解,但MyBatis实现类中添加了该注解是允许的,但要保证@Param指定的名称与SQL中的#{}占位符完全匹配;
  • 排查是否存在方法重载情况,这可能导致MyBatis无法正确绑定方法。

4. 检查多模块类加载与编译配置

确认通用模块打包后的Jar包中包含MybatisScheduledTaskRepository的字节码文件,且MyBatis所需的注解未被编译丢失:

  • 在通用模块的build.gradle中添加编译参数,保留方法参数名称(MyBatis绑定需要):
    tasks.withType(JavaCompile) {
        options.compilerArgs.add("-parameters")
    }
    

5. 确认MyBatis版本兼容性

检查通用模块与主应用模块使用的MyBatis、MyBatis-Spring-Boot-Starter版本是否一致,版本不兼容可能导致Mapper绑定逻辑失效。


内容的提问来源于stack exchange,提问作者Montana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:01:59