如何在Spring Boot+Camel流程中用注解(接口Mapper)使用MyBatis?
我之前也碰到过一模一样的问题,折腾了好一阵才搞定,咱们一步步来拆解解决:
当你用注解式MyBatis Mapper(比如@Select、@Insert这类)的时候,MyBatis会自动为每个注解方法生成一个默认的statement ID,格式是全限定接口名.方法名(举个例子:com.example.mapper.UserMapper.selectById)。
但Camel的MyBatis组件默认是按XML配置的思路找statement ID的,如果你没正确指定这个注解生成的ID,或者Camel没拿到Spring管理的MyBatis实例,就会出现“找不到statement ID”的报错。而且你直接Java调用没问题,说明Mapper本身是好的,问题出在Camel和MyBatis的整合衔接上。
下面是我验证过的一套配置流程,确保Camel能稳稳调用注解式Mapper:
1. 先把依赖配对(pom.xml)
一定要选适配你Spring Boot版本的依赖,避免版本冲突:
<dependencies> <!-- Spring Boot整合MyBatis的starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> <!-- 对应你的Spring Boot版本,比如2.7.x用这个没问题 --> </dependency> <!-- Camel Spring Boot核心starter --> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-spring-boot-starter</artifactId> <version>3.20.2</version> <!-- 和Spring Boot 2.7.x适配 --> </dependency> <!-- Camel的MyBatis组件 --> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-mybatis</artifactId> <version>3.20.2</version> </dependency> <!-- 数据库驱动,这里以MySQL为例 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies>
2. 配置MyBatis注解Mapper
有两种方式让Spring识别你的Mapper:
- 单个Mapper加注解:在你的Mapper接口上标注
@Mapper@Mapper public interface UserMapper { @Select("SELECT * FROM user WHERE id = #{id}") User selectById(@Param("id") Long id); } - 批量扫描Mapper包:在Spring Boot启动类上加
@MapperScan,指定Mapper所在的包路径,这样不用每个Mapper都加@Mapper@SpringBootApplication @MapperScan("com.example.mapper") // 替换成你的Mapper包路径 public class CamelMyBatisDemoApplication { public static void main(String[] args) { SpringApplication.run(CamelMyBatisDemoApplication.class, args); } }
然后在application.properties里配置数据库和MyBatis的基础参数:
# 数据库连接信息 spring.datasource.url=jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=123456 # 可选:开启MyBatis日志,方便调试SQL mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3. 配置Camel路由调用注解式Mapper
这里有两种常用的方式,选你觉得顺手的就行:
方式1:直接用Camel的MyBatis组件调用(指定statement ID)
关键是要把全限定接口名.方法名作为statement ID传入,同时确保Camel使用Spring管理的SqlSessionFactory:
@Component public class MyBatisRoute extends RouteBuilder { // 注入Spring自动创建的SqlSessionFactory @Autowired private SqlSessionFactory sqlSessionFactory; @Override public void configure() throws Exception { // 给Camel的MyBatis组件绑定Spring的SqlSessionFactory MyBatisComponent myBatisComponent = getContext().getComponent("mybatis", MyBatisComponent.class); myBatisComponent.setSqlSessionFactory(sqlSessionFactory); // 示例路由:用定时器触发,调用UserMapper的selectById方法 from("timer:mybatisTimer?period=5000") .setBody(constant(1L)) // 设置查询参数id=1 // 这里的statementId必须是全限定的Mapper方法名 .to("mybatis:com.example.mapper.UserMapper.selectById?parameterType=java.lang.Long") .log("查询到的用户: ${body}"); } }
方式2:直接注入Mapper实例,在Processor里调用(更灵活)
如果你觉得写长statement ID麻烦,也可以像普通Java调用那样,直接注入Mapper接口,在Camel的Processor里调用方法:
@Component public class MyBatisRoute extends RouteBuilder { // 注入Spring管理的Mapper实例 @Autowired private UserMapper userMapper; @Override public void configure() throws Exception { from("timer:mybatisTimer?period=5000") .process(exchange -> { // 直接调用Mapper的方法,和你平时Java调用完全一样 User user = userMapper.selectById(1L); exchange.getIn().setBody(user); }) .log("查询到的用户: ${body}"); } }
如果还是踩坑,按下面的步骤检查:
- 找不到statement ID:
- 确认你在Camel路由里写的statement ID是
全限定接口名.方法名,大小写要完全一致,比如com.example.mapper.UserMapper.selectById,别漏了包名。 - 看启动日志,确认Spring已经扫描到你的Mapper接口(日志里会有类似
MapperRegistry added mapper: com.example.mapper.UserMapper的记录)。
- 确认你在Camel路由里写的statement ID是
- Camel拿不到SqlSessionFactory:
- 检查你是不是用
@Autowired注入的Spring管理的SqlSessionFactory,别自己new一个,那样和Spring的上下文不打通。 - 测试数据库连接是否正常,比如用Spring Boot的健康端点看数据库状态。
- 检查你是不是用
- 参数传递错误:
- 如果Mapper方法有多个参数,一定要用
@Param给参数命名,然后在Camel里用Map或者Bean传递参数,比如:// Mapper方法 @Select("SELECT * FROM user WHERE name = #{name} AND age = #{age}") User selectByNameAndAge(@Param("name") String name, @Param("age") Integer age); // Camel路由里传参 from("direct:queryUser") .setBody().constant(Map.of("name", "张三", "age", 25)) .to("mybatis:com.example.mapper.UserMapper.selectByNameAndAge") .log("查询结果: ${body}");
- 如果Mapper方法有多个参数,一定要用
内容的提问来源于stack exchange,提问作者THM

