需求背景
SpringBoot用法:MybatisPlus框架動態數據源用法(支持多個DB,動態切換數據源)
簡介
dynamic-datasource-spring-boot-starter 是一個基於springboot的快速集成多數據源的啓動器
優勢
網上關於動態數據源的切換的文檔有很多,核心只有兩種:
- 構建多套環境,優勢是方便控制也容易集成一些簡單的分佈式事務,缺點是非動態同時代碼量較多,配置難度大。
- 基於spring提供原生的
AbstractRoutingDataSource
,參考一些文檔自己實現切換。
如果你的數據源較少,場景不復雜,選擇以上任意一種都可以
如果你需要更多特性,請嘗試本動態數據源:
- 數據源分組,適用於多種場景 純粹多庫 讀寫分離 一主多從 混合模式。
- 簡單集成Druid數據源監控多數據源,簡單集成Mybatis-Plus簡化單表,簡單集成P6sy格式化sql,簡單集成Jndi數據源。
- 簡化Druid和HikariCp配置,提供全局參數配置。
- 提供自定義數據源來源(默認使用yml或properties配置)。
- 項目啓動後能動態增減數據源。
- 使用spel動態參數解析數據源,如從session,header和參數中獲取數據源。(多租戶架構神器)
- 多層數據源嵌套切換。(一個業務ServiceA調用ServiceB,ServiceB調用ServiceC,每個Service都是不同的數據源)
- 使用正則匹配或spel表達式來切換數據源(實驗性功能)。
劣勢
- 不能使用多數據源事務(同一個數據源下能使用事務),網上其他方案也都不能提供。
- 如果你需要使用到分佈式事務,那麼你的架構應該到了微服務化的時候了。
- 如果你只是幾個數據庫,但是有強烈的需求分佈式事務,建議還是使用傳統方式自己構建多套環境集成atomic這類,網上百度很多。
約定
- 本框架只做 切換數據源 這件核心的事情,並不限制你的具體操作,切換了數據源可以做任何CRUD。
- 配置文件所有以下劃線
_
分割的數據源 首部 即爲組的名稱,相同組名稱的數據源會放在一個組下。 - 切換數據源即可是組名,也可是具體數據源名稱,切換時默認採用負載均衡機制切換。
- 默認的數據源名稱爲 master ,你可以通過spring.datasource.dynamic.primary修改。
- 方法上的註解優先於類上註解。
建議
強烈建議在 主從模式 下遵循普遍的規則,以便他人能更輕易理解你的代碼:
1. 主數據庫 建議 只執行
INSERT
UPDATE
DELETE
操作2. 從數據庫 建議 只執行
SELECT
操作
準備內容
1. 準備兩個Mysql實例
2. 數據庫初始化init.sql腳本內容(或Docker安裝MySQL數據庫)
db1-init.sql
-- for db1
drop table users;
CREATE TABLE `users` (
`username` varchar(50) NOT NULL COMMENT '用戶名',
`password` varchar(500) NOT NULL COMMENT '密碼',
`enabled` tinyint(1) NOT NULL COMMENT '是否啓用',
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `users` (`username`, `password`, `enabled`)
VALUES
('master', '123456', 1);
db2-init.sql
-- for db2
drop table users;
CREATE TABLE `users` (
`username` varchar(50) NOT NULL COMMENT '用戶名',
`password` varchar(500) NOT NULL COMMENT '密碼',
`enabled` tinyint(1) NOT NULL COMMENT '是否啓用',
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `users` (`username`, `password`, `enabled`)
VALUES
('slave', '654321', 1);
代碼演示
1. 項目目錄結構
2. pom.xml依賴組件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.md</groupId>
<artifactId>spring-boot2-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>spring-boot2-mybatis-plus-multi-datasource</artifactId>
<packaging>jar</packaging>
<name>spring-boot2-mybatis-plus-multi-datasource</name>
<description>Spring Boot, MVC, Rest API for App</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<swagger.version>2.9.2</swagger.version>
<mybatisplus.version>3.2.0</mybatisplus.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 構建成可運行的Web項目 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib-ext-spring</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!-- swagger集成 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<!-- 默認swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!-- 更易用第三方swagger-ui組件 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>
<!-- mybatis-plus集成 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 集成動態數據源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. application.yml配置文件
spring:
datasource:
dynamic:
primary: master #設置默認的數據源或者數據源組,默認值即爲master
#如果你只是單數據源,則只需要註釋掉slave相關配置就好了,這裏爲了方便演示master與slave保持相同
datasource:
master:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:33061/testdb?useUnicode=true&autoReconnect=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
username: root
password: 123456
slave_1:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:33062/testdb?useUnicode=true&autoReconnect=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
username: root
password: 123456
server:
port: 9090
4. 自動代碼生成器類
CodeGenerator.java(如不熟悉mybatis-plus框架,可以先閱讀文章:入門Mybatis-Plus快速開發框架用法)
通過此類,生成users表相應的dao,service,controller類,mapper文件等
5. UsersMapper類
定義一個方法,使用@DS註解
- 使用 @DS 切換數據源
- @DS 可以註解在方法上和類上,同時存在方法註解優先於類上註解。
- 註解在service實現或mapper接口方法上,但強烈不建議同時在service和mapper註解。
package com.md.demo.dao;
import com.md.demo.entity.vo.Users;
import java.util.List;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author Minbo
* @since 2020-03-27
*/
//@DS("slave_1")
public interface UsersMapper extends BaseMapper<Users> {
// 使用@DS註解,可以切換數據源。如果沒有配置@DS,則使用默認數據源(使用配置文件中的primary源)
// @DS 可以註解在方法上和類上,同時存在方法註解優先於類上註解
// 註解在service實現或mapper接口方法上,但強烈不建議同時在service和mapper註解
// @DS("slave_1")
// @DS("master")
public List<Users> listDbInfo();
}
UsersMapper.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.md.demo.dao.UsersMapper">
<select id="listDbInfo" resultType="com.md.demo.entity.vo.Users">
select * from users
</select>
</mapper>
6. 服務類
IUsersService:
package com.md.demo.service;
import com.md.demo.entity.vo.Users;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服務類
* </p>
*
* @author Minbo
* @since 2020-03-27
*/
public interface IUsersService extends IService<Users> {
public List<Users> listDbInfo();
}
服務實現類
package com.md.demo.service.impl;
import java.util.List;
import org.springframework.stereotype.Service;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.md.demo.dao.UsersMapper;
import com.md.demo.entity.vo.Users;
import com.md.demo.service.IUsersService;
/**
* <p>
* 服務實現類
* </p>
*
* @author Minbo
* @since 2020-03-27
*/
@Service
//@DS("slave_1")
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements IUsersService {
@Override
// @DS("master")
public List<Users> listDbInfo() {
return this.baseMapper.listDbInfo();
}
}
7. 前端控制器
UsersController
package com.md.demo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.md.demo.entity.vo.Users;
import com.md.demo.service.IUsersService;
import com.md.demo.util.JsonResult;
import com.md.demo.util.ResultCode;
import io.swagger.annotations.ApiOperation;
/**
* <p>
* 前端控制器
* </p>
*
* @author Minbo
* @since 2020-03-27
*/
@RestController
@RequestMapping("/demo/users")
public class UsersController {
@Autowired
private IUsersService usersService;
@ApiOperation(value = "獲得用戶列表信息", httpMethod = "POST")
@PostMapping("/listDbInfo")
public JsonResult listDbInfo() {
List<Users> dataList = this.usersService.listDbInfo();
if (dataList == null || dataList.size() == 0) {
return new JsonResult(ResultCode.SUCCESS_FAIL);
}
return new JsonResult(ResultCode.SUCCESS, dataList);
}
}
8. 啓動類
Application:
package com.md.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
/**
* 程序主入口
*
* @author Minbo
*
*/
@SpringBootApplication
@EnableSwaggerBootstrapUI
@MapperScan("com.md.demo.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/**
* 開啓過濾器功能
*
* @return
*/
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
/**
* 跨域過濾器
*
* @return
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
}
啓動成功輸出日誌:
就表示集成成功了
接口測試
1. 啓動項目,訪問地址:http://localhost:9090/doc.html
如果,service和mapper文件中,@DS都不啓用,則默認使用主庫
以mapper文件舉例(service同理):
package com.md.demo.dao;
import com.md.demo.entity.vo.Users;
import java.util.List;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author Minbo
* @since 2020-03-27
*/
//@DS("slave_1")
public interface UsersMapper extends BaseMapper<Users> {
// 使用@DS註解,可以切換數據源。如果沒有配置@DS,則使用默認數據源(使用配置文件中的primary源)
// @DS 可以註解在方法上和類上,同時存在方法註解優先於類上註解
// 註解在service實現或mapper接口方法上,但強烈不建議同時在service和mapper註解
// @DS("slave_1")
// @DS("master")
public List<Users> listDbInfo();
}
2. 如果啓用@DS("slave_1"),再次測試結果如下
package com.md.demo.dao;
import com.md.demo.entity.vo.Users;
import java.util.List;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author Minbo
* @since 2020-03-27
*/
//@DS("slave_1")
public interface UsersMapper extends BaseMapper<Users> {
// 使用@DS註解,可以切換數據源。如果沒有配置@DS,則使用默認數據源(使用配置文件中的primary源)
// @DS 可以註解在方法上和類上,同時存在方法註解優先於類上註解
// 註解在service實現或mapper接口方法上,但強烈不建議同時在service和mapper註解
@DS("slave_1")
// @DS("master")
public List<Users> listDbInfo();
}
完整源碼下載
官方資料
同類資料
該系列教程
我的專欄
至此,全部介紹就結束了
-------------------------------
-------------------------------
關於我(個人域名)
期望和大家一起學習,一起成長,共勉,O(∩_∩)O謝謝
歡迎交流問題,可加個人QQ 469580884,
或者,加我的羣號 751925591,一起探討交流問題
不講虛的,只做實幹家
Talk is cheap,show me the code