亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot實(shí)現(xiàn)數(shù)據(jù)源動(dòng)態(tài)切換的最佳姿勢(shì)

 更新時(shí)間:2025年03月23日 08:44:32   作者:程序員蝸牛g  
這篇文章主要為大家詳細(xì)介紹一下SpringBoot實(shí)現(xiàn)數(shù)據(jù)源動(dòng)態(tài)切換的最佳姿勢(shì),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

在介紹動(dòng)態(tài)數(shù)據(jù)源之前,我們先一起來看看多數(shù)據(jù)源在 Spring Boot 中的實(shí)現(xiàn)方式。

1.1數(shù)據(jù)庫準(zhǔn)備

創(chuàng)建兩個(gè)庫,分別是db_test_1db_test_2db_test_1數(shù)據(jù)庫中創(chuàng)建一張用戶表,腳本如下:

db_test_2數(shù)據(jù)庫中創(chuàng)建另一張賬戶表,腳本如下:

1.2工程環(huán)境準(zhǔn)備

pom.xml中添加相關(guān)的依賴包,示例如下:

<!--spring boot核心-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<!--spring boot 測試-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<!--mysql 驅(qū)動(dòng)-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>
<!--mybatis-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
<!--aspectj 注解代理-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

1.3編寫多數(shù)據(jù)源

創(chuàng)建動(dòng)態(tài)數(shù)據(jù)源服務(wù)類

首先,創(chuàng)建一個(gè)DynamicDataSource類,并繼承AbstractRoutingDataSource抽象類,同時(shí)重寫determineCurrentLookupKey()方法,代碼示例如下:

創(chuàng)建動(dòng)態(tài)數(shù)據(jù)源緩存類

創(chuàng)建一個(gè)DataSourceContextHolder類,用于緩存數(shù)據(jù)源,同時(shí)需要確保線程環(huán)境下安全

package com.example.dynamic.datasource.config;
 
publicclass DataSourceContextHolder {
 
    /**
     * 設(shè)置線程獨(dú)立變量,用于存儲(chǔ)數(shù)據(jù)源唯一標(biāo)記
     */
    privatestaticfinal ThreadLocal<String> DATASOURCE_HOLDER = new ThreadLocal<>();
 
    /**
     * 設(shè)置數(shù)據(jù)源
     * @param dataSourceName 數(shù)據(jù)源名稱
     */
    public static void set(String dataSourceName){
        DATASOURCE_HOLDER.set(dataSourceName);
    }
 
    /**
     * 獲取當(dāng)前線程的數(shù)據(jù)源
     * @return 數(shù)據(jù)源名稱
     */
    public static String get(){
        return DATASOURCE_HOLDER.get();
    }
 
    /**
     * 刪除當(dāng)前數(shù)據(jù)源
     */
    public static void remove(){
        DATASOURCE_HOLDER.remove();
    }
 
}

創(chuàng)建動(dòng)態(tài)數(shù)據(jù)源配置類

接著,創(chuàng)建一個(gè)DataSourceConfig配置類,設(shè)置動(dòng)態(tài)數(shù)據(jù)源相關(guān)的參數(shù),并注入到 Bean 工廠,代碼示例如下:

package com.example.dynamic.datasource.config;
 
@Configuration
publicclass DataSourceConfig {
 
    @Bean(name = "db1")
    @ConfigurationProperties(prefix = "spring.datasource.db1.druid")
    public DataSource db1(){
        return DruidDataSourceBuilder.create().build();
    }
 
    @Bean(name = "db2")
    @ConfigurationProperties(prefix = "spring.datasource.db2.druid")
    public DataSource db2(){
        return DruidDataSourceBuilder.create().build();
    }
 
    @Bean
    @Primary
    public DynamicDataSource createDynamicDataSource(){
        // 配置數(shù)據(jù)源集合,其中key代表數(shù)據(jù)源名稱,DataSourceContextHolder中緩存的就是這個(gè)key
        Map<Object,Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put("db1",db1());
        dataSourceMap.put("db2",db2());
 
        // 注入動(dòng)態(tài)數(shù)據(jù)源到bean工廠
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 設(shè)置默認(rèn)數(shù)據(jù)源
        dynamicDataSource.setDefaultTargetDataSource(db1());
        // 設(shè)置動(dòng)態(tài)數(shù)據(jù)源集
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        return dynamicDataSource;
    }
}

編寫相關(guān)配置變量

根據(jù)上面的配置變量,我們還需要在application.properties文件中添加相關(guān)的數(shù)據(jù)源變量,內(nèi)容如下:

排除自動(dòng)裝配數(shù)據(jù)源

需要在注解@SpringBootApplication類上排除自動(dòng)裝配數(shù)據(jù)源配置,內(nèi)容如下:

1.4利用切面代理類設(shè)置數(shù)據(jù)源

在上文中,我們采用的是手動(dòng)方式來設(shè)置數(shù)據(jù)源,在實(shí)際的業(yè)務(wù)開發(fā)中,我們通常會(huì)采用切面代理類來設(shè)置數(shù)據(jù)源,以便簡化代碼復(fù)雜度。

創(chuàng)建數(shù)據(jù)源注解

首先,定義一個(gè)數(shù)據(jù)源注解來實(shí)現(xiàn)數(shù)據(jù)源的切換,同時(shí)配置一個(gè)默認(rèn)的數(shù)據(jù)源名稱,代碼示例如下:

package com.example.dynamic.datasource.config.aop;
 
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DbSource {
 
    /**
     * 數(shù)據(jù)源key值
     * @return
     */
    String value() default "db1";
}

編寫數(shù)據(jù)源代理類

接著,基于@DbSource注解,創(chuàng)建一個(gè) AOP 代理類,所有配置該注解的方法都會(huì)被前后攔截,代碼示例如下:

package com.example.dynamic.datasource.config.aop;
 
@Order(1)
@Aspect
@Component
publicclass DbSourceAspect {
 
    privatestaticfinal Logger LOGGER = LoggerFactory.getLogger(DbSourceAspect.class);
 
 
    @Pointcut("@annotation(com.example.dynamic.datasource.config.aop.DbSource)")
    public void dynamicDataSource(){}
 
    @Around("dynamicDataSource()")
    public Object datasourceAround(ProceedingJoinPoint point) throws Throwable {
        // 獲取要切換的數(shù)據(jù)源名稱
        MethodSignature methodSignature = (MethodSignature)point.getSignature();
        Method method = methodSignature.getMethod();
        DbSource dbSource = method.getAnnotation(DbSource.class);
        LOGGER.info("select dataSource:" + dbSource.value());
        DataSourceContextHolder.set(dbSource.value());
        try {
            return point.proceed();
        } finally {
            DataSourceContextHolder.remove();
        }
    }
}

使用注解切換數(shù)據(jù)源

最后,在需要的方法上配置相關(guān)的數(shù)據(jù)源注解即可。

@Service
public class UserInfoService {
 
    @Autowired
    private UserInfoMapper userInfoMapper;
 
    @Transactional
    @DbSource(value = "db1")
    public void add(UserInfo entity){
        userInfoMapper.insert(entity);
    }
}

賬戶服務(wù)類,代碼示例如下:

@Service
public class AccountInfoService {
 
    @Autowired
    private AccountInfoMapper accountInfoMapper;
 
    @Transactional
    @DbSource(value = "db2")
    public void add(AccountInfo entity){
        accountInfoMapper.insert(entity);
    }
}

采用 aop 代理的方式來切換數(shù)據(jù)源,業(yè)務(wù)實(shí)現(xiàn)上會(huì)更加的靈活。

在上文中,我們介紹了多數(shù)據(jù)源的配置實(shí)現(xiàn)方式,這種配置方式有一個(gè)不好的地方在于:配置文件都是寫死的。

能不能改成動(dòng)態(tài)的加載數(shù)據(jù)源呢,下面我們一起來看看相關(guān)的具體實(shí)現(xiàn)方式

2.1數(shù)據(jù)庫準(zhǔn)備

首先,我們需要準(zhǔn)備一張數(shù)據(jù)源配置表。新建一個(gè)test_db數(shù)據(jù)庫,然后在數(shù)據(jù)庫中創(chuàng)建一張數(shù)據(jù)源配置表,腳本如下:

CREATE TABLE`tb_db_info` (
`id`int(11) unsignedNOTNULL AUTO_INCREMENT,
`db_name`varchar(50) DEFAULTNULL,
`db_url`varchar(200) DEFAULTNULL,
`driver_class_name`varchar(100) DEFAULTNULL,
`username`varchar(80) DEFAULTNULL,
`password`varchar(80) DEFAULTNULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3DEFAULTCHARSET=utf8mb4;

最后,初始化兩條數(shù)據(jù),方便后續(xù)數(shù)據(jù)源的查詢。

2.2修改全局配置文件

我們還是以上文介紹的工程為例,把之前自定義的配置參數(shù)刪除掉,重新基于 Spring Boot 約定的配置方式,添加相關(guān)的數(shù)據(jù)源參數(shù),內(nèi)容如下:

# 配置默認(rèn)數(shù)據(jù)源
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

2.3編寫相關(guān)的服務(wù)類

基于數(shù)據(jù)庫中tb_db_info表,編寫相關(guān)的查詢邏輯,代碼示例如下:

package com.example.dynamic.datasource.entity;
 
publicclass DbInfo {
 
    /**
     * 主鍵ID
     */
    private Integer id;
 
    /**
     * 數(shù)據(jù)庫key,即保存Map中的key
     */
    private String dbName;
 
    /**
     * 數(shù)據(jù)庫地址
     */
    private String dbUrl;
 
    /**
     * 數(shù)據(jù)庫驅(qū)動(dòng)
     */
    private String driverClassName;
 
    /**
     * 數(shù)據(jù)庫用戶名
     */
    private String username;
 
    /**
     * 數(shù)據(jù)庫密碼
     */
    private String password;
 
    // set、get方法等...
}
public interface DbInfoMapper {
 
    List<DbInfo> findAll();
}
<?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.dynamic.datasource.mapper.DbInfoMapper">
 
    <select id="findAll" resultType="com.example.dynamic.datasource.entity.DbInfo">
        select
        id
        ,db_name as dbName
        ,db_url as dbUrl
        ,driver_class_name as driverClassName
        ,username
        ,password
        from tb_db_info
        order by id
    </select>
</mapper>

2.4修改動(dòng)態(tài)數(shù)據(jù)源服務(wù)類

對(duì)DynamicDataSource類進(jìn)行一些調(diào)整,代碼如下:

public class DynamicDataSource extends AbstractRoutingDataSource {
 
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.get();
    }
 
    /**
     * 重新加載數(shù)據(jù)源集合
     * @param dbList
     */
    public void loadDataSources(List<DbInfo> dbList){
        try {
            Map<Object, Object> targetDataSourceMap = new HashMap<>();
            for (DbInfo source : dbList) {
                // 初始化數(shù)據(jù)源
                DruidDataSource dataSource = new DruidDataSource();
                dataSource.setDriverClassName(source.getDriverClassName());
                dataSource.setUrl(source.getDbUrl());
                dataSource.setUsername(source.getUsername());
                dataSource.setPassword(source.getPassword());
                dataSource.setInitialSize(1);
                dataSource.setMinIdle(1);
                dataSource.setMaxActive(5);
                dataSource.setTestWhileIdle(true);
                dataSource.setTestOnBorrow(true);
                dataSource.setValidationQuery("select 1 ");
                dataSource.init();
                targetDataSourceMap.put(source.getDbName(), dataSource);
            }
            super.setTargetDataSources(targetDataSourceMap);
            // 重新初始化resolvedDataSources對(duì)象
            super.afterPropertiesSet();
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

2.5修改動(dòng)態(tài)數(shù)據(jù)源配置類

對(duì)DataSourceConfig類也需要進(jìn)行一些調(diào)整,通過 Spring Boot 默認(rèn)的數(shù)據(jù)源配置類初始化一個(gè)數(shù)據(jù)源實(shí)例對(duì)象,代碼如下:

@Configuration
publicclass DataSourceConfig {
 
    @Autowired
    private DataSourceProperties basicProperties;
 
    /**
     * 注入動(dòng)態(tài)數(shù)據(jù)源
     * @param dataSource
     * @return
     */
    @Bean
    @Primary
    public DynamicDataSource dynamicDataSource(){
        // 獲取初始數(shù)據(jù)源
        DataSource defaultDataSource = basicProperties.initializeDataSourceBuilder().build();
 
        Map<Object,Object> targetDataSources = new HashMap<>();
        targetDataSources.put("defaultDataSource", defaultDataSource);
        // 注入動(dòng)態(tài)數(shù)據(jù)源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 設(shè)置默認(rèn)數(shù)據(jù)源
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
        // 設(shè)置動(dòng)態(tài)數(shù)據(jù)源集
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }
}

2.6配置啟動(dòng)時(shí)加載數(shù)據(jù)源服務(wù)類

以上的配置調(diào)整完成之后,我們還需要配置一個(gè)服務(wù)啟動(dòng)監(jiān)聽類,將從數(shù)據(jù)庫中查詢到的數(shù)據(jù)配置信息加載到DynamicDataSource對(duì)象中,代碼示例如下:

2.7調(diào)整 SpringBootApplication 注解配置

以上的實(shí)現(xiàn)方式,因?yàn)閱?dòng)的時(shí)候,采用的是 Spring Boot 默認(rèn)的數(shù)據(jù)源配置實(shí)現(xiàn),因此無需排除DataSourceAutoConfiguration類,可以將相關(guān)參數(shù)移除掉。

到此這篇關(guān)于SpringBoot實(shí)現(xiàn)數(shù)據(jù)源動(dòng)態(tài)切換的最佳姿勢(shì)的文章就介紹到這了,更多相關(guān)SpringBoot數(shù)據(jù)源動(dòng)態(tài)切換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java 實(shí)戰(zhàn)項(xiàng)目錘煉之仿天貓網(wǎng)上商城的實(shí)現(xiàn)流程

    Java 實(shí)戰(zhàn)項(xiàng)目錘煉之仿天貓網(wǎng)上商城的實(shí)現(xiàn)流程

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+jsp+servlet+mysql+ajax實(shí)現(xiàn)一個(gè)仿天貓網(wǎng)上商城項(xiàng)目,大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • mybatis配置獲取自增主鍵的操作方法

    mybatis配置獲取自增主鍵的操作方法

    當(dāng)需要?jiǎng)倓偛迦霐?shù)據(jù)庫的數(shù)據(jù)對(duì)應(yīng)的新增主鍵時(shí),通過配置xml文件,使數(shù)據(jù)庫返回新增主鍵id,并把主鍵id與類參數(shù)對(duì)應(yīng),本文給大家介紹了mybatis配置獲取自增主鍵的操作方法,需要的朋友可以參考下
    2024-05-05
  • Java關(guān)鍵字、標(biāo)識(shí)符、常量、變量語法詳解

    Java關(guān)鍵字、標(biāo)識(shí)符、常量、變量語法詳解

    這篇文章主要為大家詳細(xì)介紹了Java關(guān)鍵字、標(biāo)識(shí)符、常量、變量等基礎(chǔ)語法,感興趣的小伙伴們可以參考一下
    2016-09-09
  • Java中的集合框架

    Java中的集合框架

    本文主要介紹了Java中集合框架的相關(guān)知識(shí),具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-03-03
  • Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解

    Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解

    這篇文章主要介紹了Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解,幫助大家更好的理解和使用springboot,感興趣的朋友可以了解下
    2021-02-02
  • 零基礎(chǔ)如何系統(tǒng)的學(xué)習(xí)Java

    零基礎(chǔ)如何系統(tǒng)的學(xué)習(xí)Java

    這篇文章主要介紹了零基礎(chǔ)如何系統(tǒng)的學(xué)習(xí)Java,很多朋友糾結(jié)這個(gè)問題,教材書不知道從何學(xué)起,今天小編給大家分享一篇教程幫助到家梳理這方面的知識(shí)
    2020-07-07
  • 關(guān)于BeanUtils.copyProperties(source, target)的使用

    關(guān)于BeanUtils.copyProperties(source, target)的使用

    這篇文章主要介紹了關(guān)于BeanUtils.copyProperties(source, target)的使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Spring AOP 實(shí)現(xiàn)自定義注解的示例

    Spring AOP 實(shí)現(xiàn)自定義注解的示例

    這篇文章主要介紹了Spring AOP 實(shí)現(xiàn)自定義注解的示例,幫助大家更好的理解和學(xué)習(xí)使用spring框架,感興趣的朋友可以了解下
    2021-03-03
  • java過濾器中Filter的ChainFilter過濾鏈

    java過濾器中Filter的ChainFilter過濾鏈

    這篇文章主要介紹了java過濾器中Filter的ChainFilter過濾鏈,發(fā)送請(qǐng)求時(shí),如果有不符合的信息將會(huì)被filter進(jìn)行攔截,如果符合則會(huì)進(jìn)行放行。如果感興趣可以來學(xué)習(xí)一下
    2020-07-07
  • Spring如何使用三級(jí)緩存解決循環(huán)依賴

    Spring如何使用三級(jí)緩存解決循環(huán)依賴

    在Spring框架中,循環(huán)依賴是指兩個(gè)或多個(gè)Bean相互依賴,形成閉環(huán),導(dǎo)致無法完成初始化,此問題僅存在于單例Bean中,而原型Bean會(huì)拋出異常,Spring通過三級(jí)緩存及提前暴露策略解決循環(huán)依賴:一級(jí)緩存存放完全初始化的Bean
    2024-11-11

最新評(píng)論