dynamic-datasource-spring-boot-starter 是一個基於 SpringBoot 的快速集成多數據源的啓動器。其支持 Jdk 1.7+, SpringBoot 1.4.x 1.5.x 2.x.x。
官網地址:https://dynamic-datasource.com/
Gitee地址:https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter#http://dynamic-datasource.com/
GitHub地址:https://github.com/baomidou/dynamic-datasource-spring-boot-starter
功能特性:
- 支持 數據源分組 ,適用於多種場景 純粹多庫 讀寫分離 一主多從 混合模式。
- 支持無數據源啓動,支持配置懶啓動數據源(3.3.2+)。
- 支持數據庫敏感配置信息 加密 ENC()。
- 支持每個數據庫獨立初始化表結構schema和數據庫database。
- 支持 自定義註解 ,需繼承DS(3.2.0+)。
- 提供對Druid,Mybatis-Plus,P6sy,Jndi的快速集成。
- 簡化Druid和HikariCp配置,提供 全局參數配置 。配置一次,全局通用。
- 提供 自定義數據源來源 方案。
- 提供項目啓動後 動態增加移除數據源 方案。
- 提供Mybatis環境下的 純讀寫分離 方案。
- 提供使用 spel動態參數 解析數據源方案。內置spel,session,header,支持自定義。
- 支持 多層數據源嵌套切換 。(ServiceA >>> ServiceB >>> ServiceC)。
- 提供對shiro,sharding-jdbc,quartz等第三方庫集成的方案,注意事項和示例。
- 提供 基於seata的分佈式事務方案。 附:不支持原生spring事務。
- 提供 本地多數據源事務方案。 附:不支持原生spring事務(3.3.1+)。
我們這篇文章主要實現讀寫分離,一主多從的環境。
- 主數據庫建議只執行 INSERT、UPDATE、DELETE 操作。
- 從數據庫建議只執行 SELECT 操作。
一、準備數據庫
主庫:PiaoDB
從庫1:PiaoDB2
從庫2:PiaoDB3
二、導入POM文件
引入dynamic-datasource-spring-boot-starter。
<!-- 多數據源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
三、編輯配置文件
我們配置了一個主庫、兩個從庫。
- 配置文件中所有以下劃線 _ 分割的數據源“首部”即爲組的名稱,相同組名稱的數據源會放在一個組下。
- 默認的數據源名稱爲 master ,我們可以通過 spring.datasource.dynamic.primary 修改。
spring:
datasource:
dynamic:
primary: master #設置默認的數據源或者數據源組,默認值即爲master
strict: false #設置嚴格模式,默認false不啓動. 啓動後在未匹配到指定數據源時候會拋出異常,不啓動則使用默認數據源.
datasource:
master:
url: jdbc:mysql://localhost:3306/PiaoDB?serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver # 3.2.0開始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://localhost:3306/PiaoDB2?serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
slave_2:
url: jdbc:mysql://localhost:3306/PiaoDB3?serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
因爲我們使用的是阿里數據庫連接池 Druid,需要排除原生 Druid 的快速配置類。
其他第三方集成地址:集成Druid
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
某些springBoot的版本上面可能無法排除可用以下方式排除。
spring:
autoconfigure:
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
除了配置一主多從,我們還可以配置。
# 多主多從 純粹多庫(記得設置primary) 混合配置
spring: spring: spring:
datasource: datasource: datasource:
dynamic: dynamic: dynamic:
datasource: datasource: datasource:
master_1: mysql: master:
master_2: oracle: slave_1:
slave_1: sqlserver: slave_2:
slave_2: postgresql: oracle_1:
slave_3: h2: oracle_2:
四、編寫代碼
使用 @DS 切換數據源。@DS 可以註解在方法上和類上。如果同時存在,方法註解優先於類上註解。強烈建議註解在 service 實現或 mapper 接口方法上。
- @DS("xxx") 指定使用 xxx 這個數據源,xxx 可以爲組名也可以爲具體某個庫的名稱。如果是組名則切換時採用負載均衡算法切換。如果指定的組名或者庫不存在,則自動使用默認數據源(主庫)
- 如果沒有 @DS,則使用默認數據源(主庫)
- 如果設置了 @DS 但沒有指定某個組或者庫,則根據 DynamicDataSourceStrategy 策略,選擇一個從庫。默認負載均衡策略。
1、編寫Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/demo")
public class DemoController {
private final DemoService demoService;
@GetMapping("/add")
public String add() {
return demoService.add(null) + "";
}
@GetMapping("/selectGoodsInfo")
public List<GoodsInfo> selectGoodsInfo(){
return demoService.selectGoodsInfo();
}
@GetMapping("/selectMasterGoodsInfo")
public List<GoodsInfo> selectMasterGoodsInfo(){
return demoService.selectMasterGoodsInfo();
}
}
2、編寫Service
public interface DemoService {
boolean add(GoodsInfo param);
List<GoodsInfo> selectGoodsInfo();
List<GoodsInfo> selectMasterGoodsInfo();
}
@Service
@RequiredArgsConstructor
public class DemoServiceImpl implements DemoService {
private final DemoMapper demoMapper;
@DS("master")
@Override
public boolean add(GoodsInfo param) {
param = new GoodsInfo();
param.setGname("1200元秒殺華爲Pad");
param.setGnum(100);
return demoMapper.insertGoodsInfo(param);
}
@DS("slave")
@Override
public List<GoodsInfo> selectGoodsInfo() {
return demoMapper.selectGoodsInfo();
}
@DS("master")
@Override
public List<GoodsInfo> selectMasterGoodsInfo() {
return demoMapper.selectGoodsInfo();
}
}
3、編寫Mapper
@Mapper
public interface DemoMapper {
boolean insertGoodsInfo(GoodsInfo param);
List<GoodsInfo> selectGoodsInfo();
}
<?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.example.demo.mapper.DemoMapper">
<select id="selectGoodsInfo" resultType="com.example.demo.entity.GoodsInfo">
select * from t_goods_info
</select>
<insert id="insertGoodsInfo">
insert into t_goods_info (gname, gnum, gcreatetime)
values (#{gname}, #{gnum}, now());
</insert>
</mapper>
五、驗證結果
1、請求新增接口(往主庫添加數據):127.0.0.1:8086/demo/add
2、請求查詢主庫數據接口:127.0.0.1:8086/demo/selectMasterGoodsInfo
3、請求從庫數據接口(負載均衡):
第一次請求:
第二次請求:
可以發現數據輪流從兩個庫中獲取,說明負載均衡生效了。