Spring Boot多數(shù)據(jù)源Mybatis配置爬坑記錄

開(kāi)始配置

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();
    }
}

第二個(gè)數(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();
    }
}

注意,第二個(gè)數(shù)據(jù)源的 @MapperScan 必須顯示指定 sqlSessionFactory 的bean name,否則使用默認(rèn)的 sqlSessionFactory,如果 sqlSessionFactory 使用錯(cuò)誤,那么會(huì)導(dǎo)致xml和mapper接口就會(huì)對(duì)應(yīng)不上,出現(xiàn)
No MyBatis mapper was found in...或者
handle Exception : Invalid bound statement (not found):的錯(cuò)誤

  1. 配置完成,跑一下看看,果然沒(méi)錯(cuò),正常運(yùn)行,配置成功了
  2. 然后,由Jenkins 打包,部署到服務(wù)器之后,居然出錯(cuò)了,錯(cuò)誤如下
    handle Exception : Invalid bound statement (not found):
    ,難道是Jenkins的緩存,沒(méi)更新xml文件,導(dǎo)致沒(méi)找到xml文件而無(wú)法綁定?因?yàn)楸镜剡\(yùn)行正常啊。。。
  3. 登錄jenkins服務(wù)器,發(fā)現(xiàn)代碼都是最新的,一切都是正常的。
    那就應(yīng)該是 sqlSessionFactory 沒(méi)有正確注入到com.demo.adaptor.mapper包里面,從而導(dǎo)致mapper接口沒(méi)有找到xml文件。
  4. 分析發(fā)現(xiàn),由于兩個(gè) @MapperScan的掃描路徑有重復(fù),且DefaultConfig的MapperScan包括了AdaptorConfig的MapperScan,Spring boot 讀取 @Configuration進(jìn)行配置的時(shí)候是無(wú)序的,并不能保證AdaptorConfig里面的配置先于DefaultConfig執(zhí)行,導(dǎo)致com.demo.adaptor.mapper的mapper接口sqlSessionFactory里面的MapperLocations對(duì)應(yīng),而不是期望的mybatisSqlSessionFactoryAdaptor。(
    但是我本地的Springboot是按照class名字母順序進(jìn)行配置的,所以才導(dǎo)致AdaptorConfigDefaultConfig先執(zhí)行先注入,所以本地一直是運(yùn)行成的。)

解決問(wèn)題

  1. 使用@Order, 即在DefaultConfig.java同時(shí)加上@Order注解,實(shí)驗(yàn)之后,并沒(méi)有作用。
  2. 使用@Import, 即在DefaultConfig.java加上@Import(AdaptorConfig.class), 可用,但是需要去掉AdaptorConfig.java上的@Configuration注解,但是在運(yùn)行時(shí),發(fā)現(xiàn)AdaptorConfig.java里面的DataSource屬性未注入,是null。解決方案是將dataSourceAdaptor放到在DefaultConfig.java中,可行。缺點(diǎn)就是沒(méi)有做到模塊分離。
  3. 修改package名,使兩個(gè)MapperScan掃描不重復(fù)即可。缺點(diǎn)就是命名不夠規(guī)范了。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容