【SpringBoot DB系列】Mybatis多數據源配置與使用

【SpringBoot DB 系列】Mybatis 多數據源配置與使用

上一篇博文介紹 JdbcTemplate 配置多數據源的使用姿勢,在我們實際的項目開發中,使用 mybatis 來操作數據庫的可能還是非常多的,本文簡單的介紹一下 mybatis 中,多數據源的使用姿勢

  • 通過區分包路徑配合配置文件指定不同包下對應不同數據源的實現方式

I. 環境準備

1. 數據庫相關

以 mysql 爲例進行演示說明,因爲需要多數據源,一個最簡單的 case 就是一個物理庫上多個邏輯庫,本文是基於本機的 mysql 進行操作

創建數據庫teststory,兩個庫下都存在一個表money (同名同結構表,但是數據不同哦)

CREATE TABLE `money` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶名',
  `money` int(26) NOT NULL DEFAULT '0' COMMENT '錢',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

2. 項目環境

本項目藉助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA進行開發

下面是核心的pom.xml(源碼可以再文末獲取)

<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

配置文件信息application.yml

# 數據庫相關配置
spring:
  datasource:
    story:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
      username: root
      password:
    test:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
      username: root
      password:


# 日誌相關
logging:
  level:
    root: info
    org:
      springframework:
        jdbc:
          core: debug

請注意上面的數據庫配置,我們前面介紹的但數據庫配置如下,它們層級並不一樣,上面的配置需要我們自己額外進行加載解析

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:

II. 包路徑指定

這種實現方式和前文中 JdbcTemplate 的多數據源配置方式很類似,將不同數據源的 Mapper 文件拆分在不同的包中,然後在配置 mybatis 數據源及資源文件加載時,分別進行指定

1. 項目結構

本項目中使用story + test兩個數據庫,我們將不同數據庫的mapper.xml以及對應的實體相關類都分別放開,如下圖

2. 具體實現

因爲兩個庫中表結構完全一致,所以上圖中的 Entity, Mapper, Repository以及xml文件基本都是一致的,下面代碼只給出其中一份

數據庫實體類StoryMoneyEntity

@Data
public class StoryMoneyEntity {
    private Integer id;

    private String name;

    private Long money;

    private Integer isDeleted;

    private Timestamp createAt;

    private Timestamp updateAt;
}

xml 對應的 Mapper 接口StoryMoneyMapper

@Mapper
public interface StoryMoneyMapper {
    List<StoryMoneyEntity> findByIds(List<Integer> ids);
}

mapper 對應的 xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.git.hui.boot.multi.datasource.story.mapper.StoryMoneyMapper">

    <resultMap id="BaseResultMap" type="com.git.hui.boot.multi.datasource.story.entity.StoryMoneyEntity">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="money" property="money" jdbcType="INTEGER"/>
        <result column="is_deleted" property="isDeleted" jdbcType="TINYINT"/>
        <result column="create_at" property="createAt" jdbcType="TIMESTAMP"/>
        <result column="update_at" property="updateAt" jdbcType="TIMESTAMP"/>
    </resultMap>
    <sql id="money_po">
      id, `name`, money, is_deleted, create_at, update_at
    </sql>

    <select id="findByIds" parameterType="list" resultMap="BaseResultMap">
        select
        <include refid="money_po"/>
        from money where id in
        <foreach item="id" collection="list" separator="," open="(" close=")" index="">
            #{id}
        </foreach>
    </select>
</mapper>

數據庫操作封裝類StoryMoneyRepository

@Repository
public class StoryMoneyRepository {
    @Autowired
    private StoryMoneyMapper storyMoneyMapper;

    public void query() {
        List<StoryMoneyEntity> list = storyMoneyMapper.findByIds(Arrays.asList(1, 1000));
        System.out.println(list);
    }
}

接下來的重點看一下數據源以及 Mybatis 的相關配置StoryDatasourceConfig

// 請注意下面這個MapperScan,將數據源綁定在對應的包路徑下
@Configuration
@MapperScan(basePackages = "com.git.hui.boot.multi.datasource.story.mapper", sqlSessionFactoryRef = "storySqlSessionFactory")
public class StoryDatasourceConfig {

    // 從配置文件中,獲取數據庫的相關配置
    @Primary
    @Bean(name = "storyDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.story")
    public DataSourceProperties storyDataSourceProperties() {
        return new DataSourceProperties();
    }

    // DataSource的實例創建
    @Primary
    @Bean(name = "storyDataSource")
    public DataSource storyDataSource(@Qualifier("storyDataSourceProperties") DataSourceProperties storyDataSourceProperties) {
        return storyDataSourceProperties.initializeDataSourceBuilder().build();
    }

    // ibatis 對應的SqlSession工廠類
    @Primary
    @Bean("storySqlSessionFactory")
    public SqlSessionFactory storySqlSessionFactory(DataSource storyDataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(storyDataSource);
        bean.setMapperLocations(
                // 設置mybatis的xml所在位置
                new PathMatchingResourcePatternResolver().getResources("classpath*:mapping/story/*.xml"));
        return bean.getObject();
    }

    @Primary
    @Bean("storySqlSessionTemplate")
    public SqlSessionTemplate storySqlSessionTemplate(SqlSessionFactory storySqlSessionFactory) {
        return new SqlSessionTemplate(storySqlSessionFactory);
    }
}

另外一個數據源的配置文件則如下

@Configuration
@MapperScan(basePackages = "com.git.hui.boot.multi.datasource.test.mapper", sqlSessionFactoryRef = "testSqlSessionFactory")
public class TestDatasourceConfig {

    @Bean(name = "testDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.test")
    public DataSourceProperties testDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "testDataSource")
    public DataSource testDataSource(@Qualifier("testDataSourceProperties") DataSourceProperties storyDataSourceProperties) {
        return storyDataSourceProperties.initializeDataSourceBuilder().build();
    }

    @Bean("testSqlSessionFactory")
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource testDataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(testDataSource);
        bean.setMapperLocations(
                // 設置mybatis的xml所在位置
                new PathMatchingResourcePatternResolver().getResources("classpath*:mapping/test/*.xml"));
        return bean.getObject();
    }

    @Bean("testSqlSessionTemplate")
    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("testSqlSessionFactory") SqlSessionFactory testSqlSessionFactory) {
        return new SqlSessionTemplate(testSqlSessionFactory);
    }
}

3. 測試

簡單測試一下是否生效,直接在啓動類中,調用

@SpringBootApplication
public class Application {

    public Application(StoryMoneyRepository storyMoneyRepository, TestMoneyRepository testMoneyRepository) {
        storyMoneyRepository.query();
        testMoneyRepository.query();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

}

輸出如下

4. 小結

本文中介紹的多數據源方式,其實和但數據源的 mybatis 配置方式基本一致,頂多就是 SpringBoot 中,遵循默認的規範不需要我們顯示的創建DataSource實例、SqlSessionFactory實例等

上面介紹的方式,實際上就是顯示的聲明 Mybatis 配置過程,多一個數據源,就多一個相關的配置,好處是理解容易,缺點是不靈活,如果我的 Mapper 類放錯位置,可能就會出問題了

那麼有其他的方式麼,如果我希望將所有的 Mapper 放在一個包路徑下,可以支持麼?

下一篇博文,將介紹一種基於AbstractRoutingDataSource + 註解的方式來實現多數據源的支持

II. 其他

0. 項目

相關博文

源碼

1. 一灰灰 Blog

盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激

下面一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛

一灰灰blog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章