1. 程式人生 > >spring boot下mybatis配置雙資料來源

spring boot下mybatis配置雙資料來源

最近專案上遇到需要雙資料來源的來實現需求,並且需要基於spring boot,mybatis的方式來實現,在此做簡單記錄。

單一資料來源配置

單一資料來源配置的話並沒有什麼特別的,在spring boot框架下,只需要在配置檔案內新增對應的配置項即可,spring boot會自動初始化需要用到的bean。

配置資訊如下。這裡使用的是德魯伊的資料來源配置方式

#datasource配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://xxx
spring.datasource.username=root
spring.datasource.password=123456

#mybatis配置
#mybatis  xmlMapper檔案路徑
mybatis.mapper-locations=classpath:META-INF/mybatis/mapper/*Mapper.xml
mybatis.configuration.map-underscore-to-camel-case=true
#mappers mapper介面檔案路徑 多個介面時逗號隔開
mapper.mappers=com.xxxx.xxxx
mapper.not-empty=false
mapper.identity=MYSQL

在使用mapper的時候,直接使用spring的註解注入即可。

多個數據源配置

假如需要新增配置一個數據源,那麼在spring boot 框架下如何實現呢?在多資料來源的情況下,資料來源配置需要新增兩份,資料來源、mybatis等使用到的bean不能再依賴spring boot替我們完成。

多資料來源配置檔案

配置檔案改成如下,第二個資料來源的配置字首需要自定義為另外的。

#datasource 1配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://xxx
spring.datasource.username=root
spring.datasource.password=123456

#datasource 2配置,字首改為second以區分第一個資料來源
second.datasource.type=com.alibaba.druid.pool.DruidDataSource
second.datasource.driver-class-name=com.mysql.jdbc.Driver
second.datasource.url=jdbc:mysql://xxx
second.datasource.username=root
second.datasource.password=123456

多資料來源配置類

編寫第一個資料來源使用的配置類,如下所示。

對於Datasource的bean定義,需要使用@ConfigurationProperties(prefix = "spring.datasource")字首匹配來指定使用第一個資料來源的配置,同時還需要使用註解@Primary來指定當有依賴注入需要注入datasource時,優先使用@Primary註解修飾的datasource。

對於SqlSessionFactory定義,我們無法依賴spring boot做自動化配置實現,有一些動作需要我們手動處理。首先是mapper.xml檔案路徑的指定,這樣mapper接口才能註冊到mybatis容器中;假如你定義的的mapper介面沒有對應的MapperXml,你還需要手動指定mapper介面的包路徑作為引數,呼叫addMappers的方法,進行掃描註冊,手動註冊介面到mybatis容器中,一般這個過程在解析MapperXml檔案時會由mybatis框架實現。

還有就是SqlSessionTemplate,DataSourceTransactionManager的定義,第一個資料來源都需要配置為優先注入。

上面所有的配置第一個資料來源相關bean優先注入都是為了方便spring容器,管理第一個資料來源的mapper介面的代理類例項bean。spring boot實現Mapper代理類例項的註冊時,是從容器中獲取一個SqlSessionTemplatebean,然後呼叫SqlSessionTemplate.getMapper()方法獲取一個例項的,因此SqlSessionTemplate優先注入者,spring容器管理的Mapper代理類就是對應資料來源定義的。所以第一個資料來源的Mapper使用時,可以直接使用@Resource註解或者別的依賴註解來使用。


import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

/**
 * @author garine
 * @date 2018年11月16日
 **/
@Configuration
public class OdsMybatisConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    @Primary
    public DataSource odsDataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public SqlSessionFactory odsSqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //設定mapper.xml檔案路徑
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:META-INF/mybatis/mapper/*Mapper.xml"));
        //設定mapper介面的掃描包路徑
        //sqlSessionFactory.getConfiguration().addMappers("com.xxx.mapper");
        return bean.getObject();
    }

    @Bean
    @Primary
    public DataSourceTransactionManager odsTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    @Primary
    public SqlSessionTemplate odsSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    
}

下面是第二個資料來源的配置類。針對第二個資料來源配置,方法內容基本一致,但是需要注意的是,由於第一個資料來源設定了優先配置,那麼所有依賴注入預設都將注入第一個資料來源的配置,所以第二個資料來源配置需要額外指定使用何種bean注入。

datasource的定義需要使用 @Qualifier註解指定值,在依賴注入時使用 @Qualifier和指定值就可以注入目標bean。wmsSqlSessionFactory方法 使用@Qualifier(“wmsDatasource”)註解可以注入第二個資料來源bean。


import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

/**
 * @author garine
 * @date 2018年11月16日
 **/
@Configuration
public class WmsMybatisConfig {
    @Bean
    @ConfigurationProperties(prefix = "second.datasource")
    @Qualifier("wmsDatasource")
    public DataSource wmsDataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Qualifier("wmsSqlSessionFactory")
    public SqlSessionFactory wmsSqlSessionFactory(@Qualifier("wmsDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:META-INF/mybatis/wms/mapper/*Mapper.xml"));
        bean.getObject();
        SqlSessionFactory sqlSessionFactory = bean.getObject();
        //設定wms資料來源額外的mapper.java註冊
        //sqlSessionFactory.getConfiguration().addMappers("com.xx.maper");
        return sqlSessionFactory;
    }

    @Bean
    public DataSourceTransactionManager wmsTransactionManager(@Qualifier("wmsDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    @Qualifier("wmsSqlSessionTemplate")
    public SqlSessionTemplate wmsSqlSessionTemplate( @Qualifier("wmsSqlSessionFactory") SqlSessionFactory wmsSqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(wmsSqlSessionFactory);
    }

}

通過上面的配置就可以實現雙資料來源配置,下面是使用方式。

第一個資料來源定義的maper由spring容器管理,可以直接使用@Resource註解使用

第二個資料來源使用可能比較麻煩,程式碼如下。

//依賴注入第二個資料來源的SqlSession
@Resource
@Qualifier("wmsSqlSessionTemplate")
SqlSessionTemplate wmsSqlSessionTemplate;

//使用時手動獲取Mapper然後呼叫介面方法
wmsSqlSessionTemplate.getMapper(ReturnResultRecoderMapper.class).selectTest()

最後需要注意一點就是,使用上面的配置方式,mybatis的結果處理器對下劃線結果集合並沒有自動轉換為駝峰方式,需要手動在sql中定義別名。

例如實體

class People{
    private String peopleGender;
}

mybatis執行sql,結果集對映為People類。

sekect people_gender from people;

people_gender這個結果無法自動對映到peopleGender,需要執行以下sql才能對映上

sekect people_gender as peopleGendler from people;

所以這個配置過程應該是漏了某些配置導致結果處理器的名稱對映不起作用,這個問題先mark。