開始配置
application.properties大致如下:
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.two.url=jdbc:mysql://localhost:3306/demo2
spring.datasource.two.username=root
spring.datasource.two.password=root
DefaultConfig.java 如下:
package com.demo
import ...
@Configuration
@MapperScan(basePackages = {"com.demo.**.mapper"})
@EnableTransactionManagement(proxyTargetClass = true)
public class DefaultConfig {
@Bean
@ConfigurationProperties("spring.datasource.druid")
@Primary
public DataSource dataSource() {
DataSource dataSource = DruidDataSourceBuilder.create().build();
return dataSource;
}
@Bean
@Primary
public DataSourceTransactionManager dataSourceTransactionManager() {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource());
return dataSourceTransactionManager;
}
@Bean
@Primary
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:config/mapper/*.xml"));
return sessionFactory.getObject();
}
}
第二個數(shù)據(jù)源Mybatis配置
AdaptorConfig.java如下:
@Configuration
@MapperScan(value = "com.demo.adaptor.mapper",
sqlSessionFactoryRef = AcAppAdaptorConfig.SQL_SESSION_FACTORY)
@EnableTransactionManagement(proxyTargetClass = true)
public class AdaptorConfig {
public static final String SQL_SESSION_FACTORY = "mybatisSqlSessionFactoryAdaptor";
// ac-adaptor
@Bean
@ConfigurationProperties("spring.datasource.two")
public DataSource dataSourceAdaptor() {
DataSource dataSource = DruidDataSourceBuilder.create().build();
return dataSource;
}
@Bean
public DataSourceTransactionManager txManagerApp() {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSourceAdaptor());
return dataSourceTransactionManager;
}
@Bean(name = AcAppAdaptorConfig.SQL_SESSION_FACTORY)
public SqlSessionFactory mybatisSqlSessionFactoryAdaptor() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSourceAdaptor());
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(
"classpath*:config/mapper/com/petkit/adaptor/mapper/*.xml"));
return sessionFactory.getObject();
}
}
注意,第二個數(shù)據(jù)源的 @MapperScan 必須顯示指定 sqlSessionFactory 的bean name,否則使用默認的 sqlSessionFactory,如果 sqlSessionFactory 使用錯誤,那么會導致xml和mapper接口就會對應不上,出現(xiàn)
No MyBatis mapper was found in...
或者
handle Exception : Invalid bound statement (not found):
的錯誤
- 配置完成,跑一下看看,果然沒錯,正常運行,配置成功了
- 然后,由Jenkins 打包,部署到服務器之后,居然出錯了,錯誤如下
handle Exception : Invalid bound statement (not found):
,難道是Jenkins的緩存,沒更新xml文件,導致沒找到xml文件而無法綁定?因為本地運行正常啊。。。 - 登錄jenkins服務器,發(fā)現(xiàn)代碼都是最新的,一切都是正常的。
那就應該是 sqlSessionFactory 沒有正確注入到com.demo.adaptor.mapper包里面,從而導致mapper接口沒有找到xml文件。 - 分析發(fā)現(xiàn),由于兩個 @MapperScan的掃描路徑有重復,且DefaultConfig的MapperScan包括了AdaptorConfig的MapperScan,Spring boot 讀取 @Configuration進行配置的時候是無序的,并不能保證AdaptorConfig里面的配置先于DefaultConfig執(zhí)行,導致com.demo.adaptor.mapper的mapper接口sqlSessionFactory里面的MapperLocations對應,而不是期望的mybatisSqlSessionFactoryAdaptor。(
但是我本地的Springboot是按照class名字母順序進行配置的,所以才導致AdaptorConfig比DefaultConfig先執(zhí)行先注入,所以本地一直是運行成的。)
解決問題
- 使用
@Order
, 即在DefaultConfig.java
同時加上@Order
注解,實驗之后,并沒有作用。 - 使用
@Import
, 即在DefaultConfig.java
加上@Import(AdaptorConfig.class)
, 可用,但是需要去掉AdaptorConfig.java
上的@Configuration
注解,但是在運行時,發(fā)現(xiàn)AdaptorConfig.java
里面的DataSource
屬性未注入,是null。解決方案是將dataSourceAdaptor
放到在DefaultConfig.java
中,可行。缺點就是沒有做到模塊分離。 - 修改package名,使兩個MapperScan掃描不重復即可。缺點就是命名不夠規(guī)范了。