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ù)源
具體實(shí)現(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)單獨(dú)配置每個數(shù)據(jù)源信息
注意:@Primary該注解理解為默認(rèn)數(shù)據(jù)源
包路徑配置可對比參考后面的項(xiàng)目結(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ù)每個單獨(dú)的數(shù)據(jù)源的配置信息搭建mapper接口和mapper.xml文件


(6)配置mapper多數(shù)據(jù)源完成,下圖為完整的項(xiàng)目結(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)完整的項(xiàng)目結(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ù)源的實(shí)戰(zhàn)詳解
- SpringBoot自定義動態(tài)數(shù)據(jù)源的流程步驟
- SpringBoot實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換的項(xiàng)目實(shí)踐
- SpringBoot動態(tài)數(shù)據(jù)源連接測試的操作詳解
- SpringBoot實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換的方法總結(jié)
- SpringBoot中動態(tài)數(shù)據(jù)源是實(shí)現(xiàn)與用途
- springboot 動態(tài)數(shù)據(jù)源的實(shí)現(xiàn)方法(Mybatis+Druid)
- springboot動態(tài)數(shù)據(jù)源+分布式事務(wù)的實(shí)現(xiàn)
相關(guān)文章
Java多線程局域網(wǎng)聊天室的實(shí)現(xiàn)
在學(xué)習(xí)了一個學(xué)期的java以后,搞了一個多線程的聊天室,熟悉了一下服務(wù)器和客戶機(jī)的操作。感興趣的小伙伴們可以參考一下2021-06-06
解決沒有@RunWith 和 @SpringBootTest注解或失效問題
這篇文章主要介紹了解決沒有@RunWith 和 @SpringBootTest注解或失效問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
java后端如何實(shí)現(xiàn)防止接口重復(fù)提交
這篇文章主要介紹了java后端如何實(shí)現(xiàn)防止接口重復(fù)提交問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
基于Spring Security實(shí)現(xiàn)對密碼進(jìn)行加密和校驗(yàn)
我們在入門案例中,其實(shí)已經(jīng)是一個非常簡單的認(rèn)證,但是用戶名是寫死的,密碼也需要從控制臺查看,很顯然實(shí)際中并不能這么做,下面的學(xué)習(xí)中,我們來實(shí)現(xiàn)基于內(nèi)存模型的認(rèn)證以及用戶的自定義認(rèn)證,密碼加密等內(nèi)容,需要的朋友可以參考下2024-07-07

