Springboot整合多數(shù)據(jù)源代碼示例詳解
最近有個(gè)老項(xiàng)目想逐步將新業(yè)務(wù)的數(shù)據(jù)放到新的數(shù)據(jù)庫(kù),以前的業(yè)務(wù)還得連接以前的數(shù)據(jù)庫(kù),于是需要整合多數(shù)據(jù)源 。
多數(shù)據(jù)源實(shí)際上是繼承了AbstractRoutingDataSource類(lèi),這個(gè)類(lèi)最終實(shí)現(xiàn)了DataSource接口,DataSource里只有一個(gè)getConnection方法,數(shù)據(jù)庫(kù)每次訪問(wèn)的時(shí)候都要先通過(guò)這個(gè)方法獲取連接,所有多數(shù)據(jù)源就是每次訪問(wèn)數(shù)據(jù)庫(kù)之前動(dòng)態(tài)的改變數(shù)據(jù)源。
在請(qǐng)求前改變數(shù)據(jù)源當(dāng)然需要用到SpringAOP,自定義注解操作
項(xiàng)目結(jié)構(gòu)
下面上代碼:
首先是依賴(lài):
<!--數(shù)據(jù)庫(kù)連接--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--sqlserver--> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <scope>runtime</scope> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.2</version> </dependency> <!--數(shù)據(jù)庫(kù)連接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.8</version> </dependency> <!--AOP--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
yml配置數(shù)據(jù)源
server: port: 8888 spring: jackson: time-zone: GMT+8 date-format: yyyy-MM-dd HH:mm:ss datasource: druid: first: driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource jdbc-url: jdbc:mysql://rm-uf6265pj340sc9447oo.mysql.rds.54565.com:3306/dm?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf-8 username: username password: password second: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver jdbc-url: jdbc:sqlserver://39.104.203.222:1433;DatabaseName=TestTLcom username: root password: 123456 mybatis-plus: mapper-locations: classpath*:/mapper/*Mapper.xml type-aliases-package: com.zdyl.dynamicdatasourcedemo.entity global-config: #主鍵類(lèi)型 0:"數(shù)據(jù)庫(kù)ID自增", 1:"用戶(hù)輸入ID",2:"全局唯一ID (數(shù)字類(lèi)型唯一ID)", 3:"全局唯一ID UUID"; id-type: 3 #字段策略 0:"忽略判斷",1:"非 NULL 判斷"),2:"非空判斷" field-strategy: 2 #駝峰下劃線(xiàn)轉(zhuǎn)換 db-column-underline: true #刷新mapper 調(diào)試神器 refresh-mapper: true #數(shù)據(jù)庫(kù)大寫(xiě)下劃線(xiàn)轉(zhuǎn)換 #capital-mode: true #序列接口實(shí)現(xiàn)類(lèi)配置 #key-generator: com.baomidou.springboot.xxx #邏輯刪除配置 #logic-delete-value: 0 #logic-not-delete-value: 1 #自定義填充策略接口實(shí)現(xiàn) #meta-object-handler: com.baomidou.springboot.xxx #自定義SQL注入器 #sql-injector: com.baomidou.springboot.xxx configuration: map-underscore-to-camel-case: true cache-enabled: false
定義數(shù)據(jù)庫(kù)名稱(chēng)
/** * 數(shù)據(jù)庫(kù)名稱(chēng) */ public interface DataSourceNames { String FIRST = "first"; String SECOND = "second"; }
動(dòng)態(tài)數(shù)據(jù)源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * 動(dòng)態(tài)數(shù)據(jù)源 */ public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> targetDataSources) { super.setDefaultTargetDataSource(defaultTargetDataSource); super.setTargetDataSources(new HashMap<>(targetDataSources)); super.afterPropertiesSet(); } @Override protected Object determineCurrentLookupKey() { return getDataSource(); } public static String getDataSource() { return contextHolder.get(); } public static void setDataSource(String dataSource) { contextHolder.set(dataSource); } public static void clearDataSource() { contextHolder.remove(); } }
配置多數(shù)據(jù)源
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.DataSourceNames; import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.DynamicDataSource; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * 多數(shù)據(jù)源配置 */ @Configuration @MapperScan("com.zdyl.dynamicdatasourcedemo.**.mapper*") public class MybatisPluConfig { /** * 數(shù)據(jù)源配置 * @return */ @Bean @ConfigurationProperties(prefix="spring.datasource.druid.first") public DataSource firstDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix="spring.datasource.druid.second") public DataSource secondDataSource() { return DataSourceBuilder.create().build(); } @Bean @Primary public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource){ Map<String, DataSource> targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceNames.FIRST, firstDataSource); targetDataSources.put(DataSourceNames.SECOND, secondDataSource); return new DynamicDataSource(firstDataSource, targetDataSources); } /** * mybatis-plus分頁(yè)插件<br> * 文檔:http://mp.baomidou.com<br> */ @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } }
下面就是自定義注解
import java.lang.annotation.*; /** * 多數(shù)據(jù)源注解 * AOP攔截此注解更換數(shù)據(jù)源 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CurDataSource { String name() default ""; }
AOP
import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.DataSourceNames; import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.DynamicDataSource; import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.annotation.CurDataSource; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 多數(shù)據(jù)源,切面處理類(lèi) * AOP攔截多數(shù)據(jù)源注解 @CurDataSource 注解更換數(shù)據(jù)源 */ @Slf4j @Aspect @Component public class DataSourceAspect implements Ordered { /** * 切點(diǎn) */ @Pointcut("@annotation(com.zdyl.dynamicdatasourcedemo.dynamicdatasource.annotation.CurDataSource)") public void dataSourcePointCut() { } @Around("dataSourcePointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); CurDataSource curDataSource = method.getAnnotation(CurDataSource.class); if (curDataSource == null) { DynamicDataSource.setDataSource(DataSourceNames.FIRST); log.info("set datasource is " + DataSourceNames.FIRST); } else { DynamicDataSource.setDataSource(curDataSource.name()); log.info("set datasource is " + curDataSource.name()); } try { return point.proceed(); } finally { DynamicDataSource.clearDataSource(); log.info("clean datasource"); } } @Override public int getOrder() { return 1; } }
最后主啟動(dòng)了去掉數(shù)據(jù)源自動(dòng)加載
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
最后我們來(lái)跑起來(lái)請(qǐng)求一下,測(cè)試一下是否正確
@RestController public class CfgDeviceController { @Resource CfgDeviceService cfgDeviceService; @Resource CfgChargeStartInfoService cfgChargeStartInfoService; @CurDataSource(name = DataSourceNames.FIRST) @GetMapping("/test") public void getUser() { CfgDevice byId = cfgDeviceService.getById(19); System.out.println(byId.toString()); } @CurDataSource(name = DataSourceNames.SECOND) @GetMapping("/test1") public void getUser1() { CfgChargeStartInfo byId = cfgChargeStartInfoService.getById(1); System.out.println(byId.toString()); } }
**如果不加注解,使用默認(rèn)數(shù)據(jù)源
至此就整合完了
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Springboot多數(shù)據(jù)源配置之整合dynamic-datasource方式
- SpringBoot整合Mybatis實(shí)現(xiàn)多數(shù)據(jù)源配置與跨數(shù)據(jù)源事務(wù)實(shí)例
- Springboot整合JPA配置多數(shù)據(jù)源流程詳解
- SpringBoot整合Mybatis Plus多數(shù)據(jù)源的實(shí)現(xiàn)示例
- SpringBoot+Mybatis plus實(shí)現(xiàn)多數(shù)據(jù)源整合的實(shí)踐
- SpringBoot使用Atomikos技術(shù)整合多數(shù)據(jù)源的實(shí)現(xiàn)
- SpringBoot2整合JTA組件實(shí)現(xiàn)多數(shù)據(jù)源事務(wù)管理
- Springboot整合多數(shù)據(jù)源配置流程詳細(xì)講解
相關(guān)文章
解決SpringBoot log4j日志沒(méi)生成的問(wèn)題
這篇文章主要介紹了解決SpringBoot log4j日志沒(méi)生成的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Java如何獲取數(shù)組和字符串的長(zhǎng)度(length還是length())
這篇文章主要介紹了Java如何獲取數(shù)組和字符串的長(zhǎng)度(length還是length()),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12詳談Java中Object類(lèi)中的方法以及finalize函數(shù)作用
下面小編就為大家?guī)?lái)一篇詳談Java中Object類(lèi)中的方法以及finalize函數(shù)作用。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04文件上傳SpringBoot后端MultipartFile參數(shù)報(bào)空問(wèn)題的解決辦法
這篇文章主要介紹了文件上傳SpringBoot后端MultipartFile參數(shù)報(bào)空問(wèn)題的解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11java實(shí)現(xiàn)堆排序以及時(shí)間復(fù)雜度的分析
本文主要介紹了java實(shí)現(xiàn)堆排序以及時(shí)間復(fù)雜度,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12SSH框架網(wǎng)上商城項(xiàng)目第5戰(zhàn)之商品類(lèi)別級(jí)聯(lián)查詢(xún)和分頁(yè)功能
SSH框架網(wǎng)上商城項(xiàng)目第5戰(zhàn)之商品類(lèi)別級(jí)聯(lián)查詢(xún)和分頁(yè)功能,寫(xiě)一下CategoryServiceImpl實(shí)現(xiàn)類(lèi),完成數(shù)據(jù)庫(kù)的級(jí)聯(lián)查詢(xún),感興趣的小伙伴們可以參考一下2016-05-05Mybatis-plus+通用mapper(tk.mybatis)的使用
本文主要介紹了Mybatis-plus+通用mapper(tk.mybatis)的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧<BR>2024-03-03