springboot配置多數(shù)據(jù)源(靜態(tài)和動態(tài)數(shù)據(jù)源)
背景
在開發(fā)過程中,很多時候都會有垮數(shù)據(jù)庫操作數(shù)據(jù)的情況,需要同時配置多套數(shù)據(jù)源,即多個數(shù)據(jù)庫,保證不同的業(yè)務(wù)在不同的數(shù)據(jù)庫執(zhí)行操作,通過mapper來靈活的切換數(shù)據(jù)源。
本文以sqlserver和mysql混合數(shù)據(jù)源配置為例。
配置多數(shù)據(jù)源方案
1、通過mapper配置數(shù)據(jù)源
2、配置動態(tài)數(shù)據(jù)源
具體實現(xiàn)
1)、 通過mapper配置數(shù)據(jù)源
(1)maven配置
? ? ? ? <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>(2)服務(wù)配置文件,application.yml
server:
port: 9900
spring:
datasource:
db1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc-url: jdbc:sqlserver://localhost:10009;DatabaseName=test
username: sa
password: 654321
db2:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test2?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowMultiQueries=true
username: root
password: 123456(3)添加數(shù)據(jù)庫配置
@Configuration
public class DataSourceConfig {
@Bean(name = "maindb")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource businessDbDataSource() {
return new HikariDataSource();
}
@Bean(name = "seconddb")
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource newhomeDbDataSource() {
return new HikariDataSource();
}
}(4)單獨配置每個數(shù)據(jù)源信息
注意:@Primary該注解理解為默認(rèn)數(shù)據(jù)源
包路徑配置可對比參考后面的項目結(jié)構(gòu)截圖
@Configuration
@MapperScan(basePackages = {"com.gxin.datasource.dao.maindb"}, sqlSessionFactoryRef = "sqlSessionFactoryMaindb")
public class DatasourceMainConfig {
@Autowired
@Qualifier("maindb")
private DataSource dataSourceMaindb;
@Bean
@Primary
public SqlSessionFactory sqlSessionFactoryMaindb() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSourceMaindb);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/maindb/*.xml"));
// 打印sql日志
// org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
// configuration.setLogImpl(StdOutImpl.class);
// factoryBean.setConfiguration(configuration);
return factoryBean.getObject();
}
@Bean
@Primary
public SqlSessionTemplate sqlSessionTemplateMaindb() throws Exception {
return new SqlSessionTemplate(sqlSessionFactoryMaindb());
}
}@Configuration
@MapperScan(basePackages = {"com.gxin.datasource.dao.seconddb"}, sqlSessionFactoryRef = "sqlSessionFactorySeconddb")
public class DatasourceSecondConfig {
@Autowired
@Qualifier("seconddb")
private DataSource dataSourceSeconddb;
@Bean
public SqlSessionFactory sqlSessionFactorySeconddb() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSourceSeconddb);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/seconddb/*.xml"));
// 打印sql日志
// org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
// configuration.setLogImpl(StdOutImpl.class);
// factoryBean.setConfiguration(configuration);
return factoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplateSeconddb() throws Exception {
return new SqlSessionTemplate(sqlSessionFactorySeconddb());
}
}(5)根據(jù)每個單獨的數(shù)據(jù)源的配置信息搭建mapper接口和mapper.xml文件


(6)配置mapper多數(shù)據(jù)源完成,下圖為完整的項目結(jié)構(gòu)

2)、 配置動態(tài)數(shù)據(jù)源
(1)maven配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>(2)服務(wù)配置文件,application.yml
server:
port: 9901
spring:
main:
allow-bean-definition-overriding: true
datasource:
db1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc-url: jdbc:sqlserver://localhost:10009;DatabaseName=test
username: sa
password: 654321
db2:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test2?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowMultiQueries=true
username: root
password: 123456(3)添加數(shù)據(jù)源列表
public interface DataSourceConstant {
/**
* 默認(rèn)數(shù)據(jù)庫
*/
String MAIN = "MAIN";
/**
* 第二數(shù)據(jù)庫
*/
String SECOND = "SECOND";
}(4)動態(tài)數(shù)據(jù)源數(shù)據(jù)庫信息配置
@Configuration
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
public class DynamicDataSourceConfig {
// 核心數(shù)據(jù)庫
@Bean(name = DataSourceConstant.MAIN)
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource getMAINDataSource() {
return new HikariDataSource();
}
// 第二數(shù)據(jù)庫
@Bean(name = DataSourceConstant.SECOND)
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource getSECONDDataSource() {
return new HikariDataSource();
}
@Bean
@Primary
public DataSource dynamicDataSource() {
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(DataSourceConstant.MAIN, getMAINDataSource());
dataSourceMap.put(DataSourceConstant.SECOND, getSECONDDataSource());
//設(shè)置動態(tài)數(shù)據(jù)源
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(dataSourceMap);
dynamicDataSource.setDefaultTargetDataSource(getMAINDataSource());
return dynamicDataSource;
}
}(5)添加動態(tài)數(shù)據(jù)源策略獲取配置,繼承AbstractRoutingDataSource
@Component
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
// 此處暫時返回固定 master 數(shù)據(jù)源, 后面按動態(tài)策略修改
return DynamicDataSourceContextHolder.getContextKey();
}
}(6)數(shù)據(jù)源切換策略配置
public class DynamicDataSourceContextHolder {
/**
* 動態(tài)數(shù)據(jù)源名稱上下文
*/
private static final ThreadLocal<String> DATASOURCE_CONTEXT_KEY_HOLDER = new ThreadLocal<>();
/**
* 設(shè)置/切換數(shù)據(jù)源
*/
public static void setContextKey(String key) {
DATASOURCE_CONTEXT_KEY_HOLDER.set(key);
}
/**
* 獲取數(shù)據(jù)源名稱
*/
public static String getContextKey() {
String key = DATASOURCE_CONTEXT_KEY_HOLDER.get();
return key == null ? DataSourceConstant.MAIN : key;
}
/**
* 刪除當(dāng)前數(shù)據(jù)源名稱
*/
public static void removeContextKey() {
DATASOURCE_CONTEXT_KEY_HOLDER.remove();
}
}(6.1) 這里寫掉了,補(bǔ)充數(shù)據(jù)庫會話配置
@Configuration
public class SqlSessionConfig {
@Autowired
private DynamicDataSource source;
public SqlSessionConfig() {
}
@Bean(name = {"sqlSessionFactoryBean"})
public SqlSessionFactoryBean getSessionFactory() throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(this.source);
factory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
// 打印sql日志
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLogImpl(StdOutImpl.class);
factory.setConfiguration(configuration);
return factory;
}
@Bean(name = {"sqlSession"})
public SqlSessionTemplate getSqlSession() throws Exception {
return new SqlSessionTemplate(Objects.requireNonNull(getSessionFactory().getObject()));
// SqlSessionFactory factory = this.getSessionFactory().getObject();
// return new SqlSessionTemplate(factory, ExecutorType.BATCH);
}
@Bean
public DataSourceTransactionManager getDataSourceTransaction() {
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(this.source);
return manager;
}
}(7) 添加切換數(shù)據(jù)源標(biāo)識注解,默認(rèn)為MAIN數(shù)據(jù)源
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DBS {
/**
* 數(shù)據(jù)源名稱
*/
String value() default DataSourceConstant.MAIN;
}(8)通過配置的數(shù)據(jù)源標(biāo)識注解,動態(tài)切換數(shù)據(jù)源
@Aspect
@Component
public class DynamicDataSourceAspect {
@Pointcut("@annotation(com.gxin.dynamicdatasource.config.DBS)")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
String dsKey = getDSAnnotation(joinPoint).value();
DynamicDataSourceContextHolder.setContextKey(dsKey);
try {
return joinPoint.proceed();
} finally {
DynamicDataSourceContextHolder.removeContextKey();
}
}
/**
* 根據(jù)類或方法獲取數(shù)據(jù)源注解
*/
private DBS getDSAnnotation(ProceedingJoinPoint joinPoint) {
Class<?> targetClass = joinPoint.getTarget().getClass();
DBS dsAnnotation = targetClass.getAnnotation(DBS.class);
// 先判斷類的注解,再判斷方法注解
if (Objects.nonNull(dsAnnotation)) {
return dsAnnotation;
} else {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
return methodSignature.getMethod().getAnnotation(DBS.class);
}
}
}(9)到此動態(tài)數(shù)據(jù)源配置完成,一下的為使用情況,需要使用哪個數(shù)據(jù)源添加注解配置即可
@Repository
public interface TestMapper {
int getModelcount();
@DBS(DataSourceConstant.SECOND)
int getUsercount();
}(10)service層
@Service
public class ServiceInfo {
@Autowired
private TestMapper mainMapper;
public void datasource() {
int modelcount = mainMapper.getModelcount();
System.out.println(modelcount);
int usercount = mainMapper.getUsercount();
System.out.println(usercount);
}
}(11)mapper. xml結(jié)構(gòu)目錄

(12)完整的項目結(jié)構(gòu)截圖

到此這篇關(guān)于springboot配置多數(shù)據(jù)源(靜態(tài)和動態(tài)數(shù)據(jù)源)的文章就介紹到這了,更多相關(guān)springboot 多數(shù)據(jù)源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中動態(tài)數(shù)據(jù)源配置與使用詳解
- SpringBoot配置動態(tài)數(shù)據(jù)源的實戰(zhàn)詳解
- SpringBoot自定義動態(tài)數(shù)據(jù)源的流程步驟
- SpringBoot實現(xiàn)動態(tài)數(shù)據(jù)源切換的項目實踐
- SpringBoot動態(tài)數(shù)據(jù)源連接測試的操作詳解
- SpringBoot實現(xiàn)動態(tài)數(shù)據(jù)源切換的方法總結(jié)
- SpringBoot中動態(tài)數(shù)據(jù)源是實現(xiàn)與用途
- springboot 動態(tài)數(shù)據(jù)源的實現(xiàn)方法(Mybatis+Druid)
- springboot動態(tài)數(shù)據(jù)源+分布式事務(wù)的實現(xiàn)
相關(guān)文章
Spring?Boot數(shù)據(jù)響應(yīng)問題實例詳解
這篇文章主要給大家介紹了關(guān)于Spring?Boot數(shù)據(jù)響應(yīng)問題的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-03-03
RabbitMQ開啟SSL與SpringBoot連接測試的配置方法
本文基于 CentOS 7 + Git + OpenSSL + yum 安裝的 RabbitMQ,需要讀者提交安裝好。其他方式也可變通參考本文。對RabbitMQ開啟SSL與SpringBoot連接測試相關(guān)知識感興趣的朋友一起看看吧2022-01-01
Java不用算數(shù)運(yùn)算符來實現(xiàn)求和方法
我們都知道,Java的運(yùn)算符除了具有優(yōu)先級之外,還有一個結(jié)合性的特點。當(dāng)一個表達(dá)式中出現(xiàn)多種運(yùn)算符時,執(zhí)行的先后順序不僅要遵守運(yùn)算符優(yōu)先級別的規(guī)定,還要受運(yùn)算符結(jié)合性的約束,以便確定是自左向右進(jìn)行運(yùn)算還是自右向左進(jìn)行運(yùn)算,但是如果不用運(yùn)算符怎么求和呢2022-04-04
Java實現(xiàn)Html轉(zhuǎn)Pdf的方法
這篇文章主要介紹了Java實現(xiàn)Html轉(zhuǎn)Pdf的方法,實例分析了java基于ITextRenderer類操作頁面及系統(tǒng)自帶字體生成pdf文件的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07
springboot+rabbitmq實現(xiàn)智能家居實例詳解
這篇文章主要為大家介紹了springboot+rabbitmq實現(xiàn)智能家居的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
Java中的強(qiáng)制類型轉(zhuǎn)換 大數(shù)轉(zhuǎn)小數(shù)
這里主要討論一下大數(shù)轉(zhuǎn)小數(shù),比如int類型轉(zhuǎn)short類型。小數(shù)轉(zhuǎn)大數(shù),如short 轉(zhuǎn) int不做討論,需要的朋友可以參考下2020-02-02

