SpringBoot采用Dynamic-Datasource方式實現(xiàn)多JDBC數(shù)據(jù)源
1.1 特性
- 提供本地多數(shù)據(jù)源事務(wù)方案。由AOP實現(xiàn)
- 支持數(shù)據(jù)源分組,適用于多種場景,如多庫讀寫分離、一主多從(實現(xiàn)了數(shù)據(jù)庫負載均衡算法)、混合模式
- 提供自定義數(shù)據(jù)源來源方案(如全從數(shù)據(jù)庫加載)
- 提供項目啟動后動態(tài)增加移除數(shù)據(jù)源方案
- 支持數(shù)據(jù)庫敏感配置信息加密(可自定義)ENC()
- 支持每個數(shù)據(jù)庫獨立初始化表結(jié)構(gòu)schema和數(shù)據(jù)庫database
- 支持無數(shù)據(jù)源啟動,支持懶加載數(shù)據(jù)源(需要的時候再創(chuàng)建連接)
- 支持自定義注解,需繼承DS(3.2.0+)
- 提供并簡化對Druid、HikariCp、BeeCp、Dbcp2的快速集成
- 提供對Mybatis-Plus、Quartz、ShardingJdbc、P6sy、Jndi等組件的集成方案
- 提供Mybatis環(huán)境下的純讀寫分離方案
- 提供使用spel動態(tài)參數(shù)解析數(shù)據(jù)源方案。內(nèi)置spel、session、header,支持自定義
- 支持多層數(shù)據(jù)源嵌套切換。(ServiceA >>> ServiceB >>> ServiceC)
- 支持Seata分布式事務(wù)
1.2 Mysql數(shù)據(jù)準備
分別創(chuàng)建read_db.user和write_db.user,并向read_db.user寫入數(shù)據(jù)
mysql> create database read_db;
Query OK, 1 row affected (0.14 sec)
mysql> create database write_db;
Query OK, 1 row affected (0.01 sec)
mysql> create table read_db.user (
-> id bigint(20) auto_increment not null comment '主鍵ID',
-> name varchar(30) null default null comment '姓名',
-> primary key (id)
-> );
Query OK, 0 rows affected, 1 warning (0.29 sec)
mysql>
mysql> insert into read_db.user (id, name) values
-> (1, 'read_name1'),
-> (2, 'read_name2'),
-> (3, 'read_name3'),
-> (4, 'read_name4'),
-> (5, 'read_name5');
Query OK, 5 rows affected (0.16 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql>
mysql> create table write_db.user (
-> id bigint(20) auto_increment not null comment '主鍵ID',
-> name varchar(30) null default null comment '姓名',
-> primary key (id)
-> );
Query OK, 0 rows affected, 1 warning (0.04 sec)
mysql> 2.2 通過Dynamic-Datasource實現(xiàn)多JDBC數(shù)據(jù)源
2.2.1 pom.xml依賴
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>可以看到自動添加了spring-boot-starter-jdbc、spring-boot-starter-aop依賴

2.2.2 application.properties配置
通過dynamic方式,指定了datasource1和datasource2兩個DataSource
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource # 設(shè)置默認的數(shù)據(jù)源。默認是master spring.datasource.dynamic.primary=datasource1 # 嚴格匹配數(shù)據(jù)源, 默認false。true表示未匹配到指定數(shù)據(jù)源時拋異常, false表示使用默認數(shù)據(jù)源 spring.datasource.dynamic.strict=true # 用于讀的數(shù)據(jù)庫 spring.datasource.dynamic.datasource.datasource1.url=jdbc:mysql://192.168.28.12:3306/read_db spring.datasource.dynamic.datasource.datasource1.username=root spring.datasource.dynamic.datasource.datasource1.password=Root_123 spring.datasource.dynamic.datasource.datasource1.driver-class-name=com.mysql.cj.jdbc.Driver # 用于寫的數(shù)據(jù)庫 spring.datasource.dynamic.datasource.datasource2.url=jdbc:mysql://192.168.28.12:3306/write_db spring.datasource.dynamic.datasource.datasource2.username=root spring.datasource.dynamic.datasource.datasource2.password=Root_123 spring.datasource.dynamic.datasource.datasource2.driver-class-name=com.mysql.cj.jdbc.Driver
2.2.3 使用@DS注解選擇DataSource
可以在Service的類或方法上(優(yōu)先級更高)使用@DS注解選擇DataSource
2.2.4 使用@Transactional + @DSTransactional實現(xiàn)事務(wù)
可以在Service的類或方法上(優(yōu)先級更高)使用@Transactional實現(xiàn)事務(wù)。對異常的捕獲后,通過 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 進行手動回滾
@Transactional注解會讓@DS的多數(shù)據(jù)源切換失效,雖然可以通過 @Transactional(propagation = Propagation.REQUIRES_NEW) 開啟一個內(nèi)部子事務(wù)來使@DS切換數(shù)據(jù)源,但是大部分場景不適用
@DSTransactional能和@DS多數(shù)據(jù)源切換配合使用,@DSTransactional注解最好使用在方法上(類似好像不生效),@DSTransactional注解不能對異常進行捕獲手動回滾,只能自動回滾然后拋出異常
2.3 動態(tài)數(shù)據(jù)源測試
2.3.1 創(chuàng)建User類
package com.hh.springboottest.myController;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
public class User {
private Long id;
private String name;
}2.3.2 Mapper接口實現(xiàn)
package com.hh.springboottest.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hh.springboottest.myController.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}2.3.3 Service實現(xiàn)
Service接口實現(xiàn)
package com.hh.springboottest.service;
import com.hh.springboottest.myController.User;
public interface UserService {
public User getUser(Long id);
public void saveMultiUser();
}ServiceImpl實現(xiàn)類。說明如下:
- @DS(“datasource1”)注解,讓userMapper.selectById使用了datasource1數(shù)據(jù)源
- @DS(“datasource2”)注解,讓userMapper.insert使用了datasource2數(shù)據(jù)源
- @Transactional注解,當userMapper.insert(user1)執(zhí)行成功,userMapper.insert(user2)執(zhí)行失敗,會回滾userMapper.insert(user1)的操作
package com.hh.springboottest.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.hh.springboottest.mapper.UserMapper;
import com.hh.springboottest.myController.User;
import com.hh.springboottest.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@DS("datasource1")
@Override
public User getUser(Long id) {
return userMapper.selectById(id);
}
@Transactional
@DS("datasource2")
@Override
public void saveMultiUser() {
User user2 = new User(2L, "write_name2");
userMapper.insert(user2);
User user3 = new User(3L, "write_name3");
userMapper.insert(user3);
}
}2.3.4 測試
package com.hh.springboottest;
import com.hh.springboottest.myController.User;
import com.hh.springboottest.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
public class MyApplicationTest {
@Autowired
UserService userService;
@Test
public void dynamicDataSourceTest() {
User user = userService.getUser(1L);
log.info("獲取到的用戶為:{}", user);
userService.saveMultiUser();
}
}運行程序,結(jié)果如下:
2022-11-24 09:16:15.733 INFO 33760 --- [ main] com.hh.springboottest.MyApplicationTest : 獲取到的用戶為:User(id=1, name=read_name1)
2022-11-24 09:16:15.857 INFO 33760 --- [ionShutdownHook] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource start closing ....
2022-11-24 09:16:15.861 INFO 33760 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closing ...
2022-11-24 09:16:15.866 INFO 33760 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closed
2022-11-24 09:16:15.866 INFO 33760 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closing ...
2022-11-24 09:16:15.867 INFO 33760 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closed
2022-11-24 09:16:15.867 INFO 33760 --- [ionShutdownHook] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource all closed success,bye
同時查看write_db.user表,數(shù)據(jù)如下:
mysql> select * from write_db.user; +----+--------------+ | id | name | +----+--------------+ | 1 | write_name1 | | 2 | write_name2 | | 3 | write_name3 | +----+--------------+ 3 rows in set (0.11 sec) mysql>
2.4 removeDataSource刪除DataSource
通過DynamicRoutingDataSource的removeDataSource方法刪除DataSource
package com.hh.springboottest.service.impl;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
@Service
public class DataSourceServiceImpl implements DataSourceService {
@Autowired
DataSource dataSource;
public void removeDataSource(String dataSourceName) {
DynamicRoutingDataSource dynamicRoutingDataSource =
(DynamicRoutingDataSource) dataSource;
dynamicRoutingDataSource.removeDataSource(dataSourceName);
}
}到此這篇關(guān)于SpringBoot采用Dynamic-Datasource方式實現(xiàn)多JDBC數(shù)據(jù)源的文章就介紹到這了,更多相關(guān)SpringBoot Dynamic-Datasource JDBC數(shù)據(jù)源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Intellij IDEA的Facets和Artifacts
這篇文章主要介紹了Intellij IDEA的Facets和Artifacts的相關(guān)知識,本文通過實例給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-09-09
Java中使用正則表達式獲取網(wǎng)頁中所有圖片的路徑
這篇文章主要介紹了Java中使用正則表達式獲取網(wǎng)頁中所有圖片的路徑,本文直接給出實例代碼,需要的朋友可以參考下2015-06-06
Springboot項目平滑關(guān)閉及自動化關(guān)閉腳本
這篇文章主要為大家詳細介紹了Springboot項目平滑關(guān)閉及自動化關(guān)閉腳本,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-05-05

