将MyBatis Mapper作为多模块通用仓库时出现绑定异常的问询
问题排查:MyBatis Invalid bound statement 异常
问题背景
我需要开发一个可在多模块中复用的通用模块,其中多数模块基于MyBatis,部分模块使用Spring Data + Hibernate。针对MyBatis场景的实现步骤如下:
- 定义通用仓库接口
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); }
- 编写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); // 其他重写方法省略... }
- 在通用模块中创建
ScheduledTaskService,依赖ScheduledTaskRepository接口实现业务逻辑 - 通用模块的
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
相关产品推荐
相关产品推荐

