自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring Boot 實(shí)現(xiàn)數(shù)據(jù)源動態(tài)切換的最佳姿勢!

開發(fā) 前端
隨著用戶需求的不斷變化,在很多的業(yè)務(wù)環(huán)境下,我們需要用到動態(tài)數(shù)據(jù)源,比如多租戶的場景,簡單的說就是,多個租戶除了數(shù)據(jù)源不一樣,服務(wù)代碼和數(shù)據(jù)表結(jié)構(gòu)完全一致。這個時候采用動態(tài)數(shù)據(jù)源方案,可以極大的簡化服務(wù)工程量。

一、背景介紹

隨著用戶需求的不斷變化,在很多的業(yè)務(wù)環(huán)境下,我們需要用到動態(tài)數(shù)據(jù)源,比如多租戶的場景,簡單的說就是,多個租戶除了數(shù)據(jù)源不一樣,服務(wù)代碼和數(shù)據(jù)表結(jié)構(gòu)完全一致。這個時候采用動態(tài)數(shù)據(jù)源方案,可以極大的簡化服務(wù)工程量。

圖片圖片

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

二、多數(shù)據(jù)源實(shí)現(xiàn)介紹

服務(wù)框架采用 Spring Boot + Mybatis + Druid 來實(shí)現(xiàn)數(shù)據(jù)庫的訪問和操作,數(shù)據(jù)庫采用 Mysql 來存儲和查詢,程序環(huán)境如下:

  • Mysql:5.7
  • JDK:1.8
  • Spring Boot:2.1.0
  • Mybatis:3.5.0
  • Druid:1.1.10

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

為了便于演示,在 Mysql 數(shù)據(jù)庫中創(chuàng)建兩個庫,分別是db_test_1和db_test_2。

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

CREATE TABLE`tb_user_info` (
`id`int(11) unsignedNOTNULL,
`user_name`varchar(50) DEFAULTNULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

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

CREATE TABLE`tb_account_info` (
`id`int(11) unsignedNOTNULL,
`account_name`varchar(50) DEFAULTNULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

創(chuàng)建完成之后,確保數(shù)據(jù)庫的 IP、端口、用戶和密碼,能遠(yuǎn)程正常聯(lián)通。

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

以Spring Boot框架為基礎(chǔ),創(chuàng)建一個服務(wù)工程,并在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ū)動-->
<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>

2.3、編寫多數(shù)據(jù)源配置服務(wù)

Spring Boot 支持根據(jù)一定的規(guī)則來動態(tài)選擇數(shù)據(jù)源,用戶可以通過繼承AbstractRoutingDataSource抽象類并重寫determineCurrentLookupKey()方法來完成數(shù)據(jù)源的切換。

在每次執(zhí)行數(shù)據(jù)庫操作之前,它會先調(diào)用determineCurrentLookupKey()抽象方法,根據(jù)初始化時設(shè)置的數(shù)據(jù)源集合,通過其中的key來決定使用哪個數(shù)據(jù)源。

具體實(shí)現(xiàn)方式如下!

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

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

package com.example.dynamic.datasource.config;

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.get();
    }
}

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

然后,創(chuàng)建一個DataSourceContextHolder類,用于緩存數(shù)據(jù)源,同時需要確保線程環(huán)境下安全,這里采用ThreadLocal線程本地變量來實(shí)現(xiàn)數(shù)據(jù)源key的緩存,代碼示例如下:

package com.example.dynamic.datasource.config;

publicclass DataSourceContextHolder {

    /**
     * 設(shè)置線程獨(dú)立變量,用于存儲數(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();
    }

}

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

接著,創(chuàng)建一個DataSourceConfig配置類,設(shè)置動態(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中緩存的就是這個key
        Map<Object,Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put("db1",db1());
        dataSourceMap.put("db2",db2());

        // 注入動態(tài)數(shù)據(jù)源到bean工廠
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 設(shè)置默認(rèn)數(shù)據(jù)源
        dynamicDataSource.setDefaultTargetDataSource(db1());
        // 設(shè)置動態(tài)數(shù)據(jù)源集
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        return dynamicDataSource;
    }
}

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

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

# 數(shù)據(jù)庫源1
spring.datasource.db1.druid.url=jdbc:mysql://localhost:3306/db_test_1
spring.datasource.db1.druid.username=root
spring.datasource.db1.druid.password=root
spring.datasource.db1.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.db1.druid.initial-size=1
spring.datasource.db1.druid.min-idle=1
spring.datasource.db1.druid.max-active=5
spring.datasource.db1.druid.max-wait=60000

# 數(shù)據(jù)庫源2
spring.datasource.db2.druid.url=jdbc:mysql://localhost:3306/db_test_2
spring.datasource.db2.druid.username=root
spring.datasource.db2.druid.password=root
spring.datasource.db2.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.db2.druid.initial-size=1
spring.datasource.db2.druid.min-idle=1
spring.datasource.db2.druid.max-active=5
spring.datasource.db2.druid.max-wait=60000

2.3.5、排除自動裝配數(shù)據(jù)源

默認(rèn)情況下,Spring Boot 啟動的時候會自動加載數(shù)據(jù)源配置,因?yàn)槲覀儧]有按照約定配置指定的數(shù)據(jù)源參數(shù),當(dāng)啟動服務(wù)的時候會報錯。

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

package com.example.dynamic.datasource;

@MapperScan("com.example.dynamic.datasource.mapper")
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2.3.6、業(yè)務(wù)相關(guān)服務(wù)類

最后基于上文數(shù)據(jù)庫中創(chuàng)建的表,編寫相關(guān)的entity、service和dao層代碼,以便于后續(xù)驗(yàn)證數(shù)據(jù)源的切換操作。

以用戶表的新增操作為例,代碼如下:

package com.example.dynamic.datasource.service;

@Service
public class UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Transactional
    public void insert(UserInfo entity){
        userInfoMapper.insert(entity);
    }
}

賬戶表的新增操作,代碼如下:

package com.example.dynamic.datasource.service;

@Service
public class AccountInfoService {

    @Autowired
    private AccountInfoMapper accountInfoMapper;

    @Transactional
    public void insert(AccountInfo entity){
        accountInfoMapper.insert(entity);
    }
}

entity和dao層代碼就不再貼進(jìn)來了,比較簡單。

2.4、編寫單元測試

最后我們編寫一個單元測試,驗(yàn)證一下代碼的正確性,示例如下:

package com.example.dynamic.datasource.junit;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DynamicDataSourceJunit {

    @Autowired
    private AccountInfoService accountInfoService;

    @Autowired
    private UserInfoService userInfoService;

    @Test
    public void testUserInfo(){
        try {
            // 1.設(shè)置需要切換的數(shù)據(jù)源
            DataSourceContextHolder.set("db1");
            // 2.執(zhí)行插入操作
            userInfoService.insert(new UserInfo(1, "張三"));
        } finally {
            // 3.操作完成之后,移除本地線程緩存的數(shù)據(jù)源
            DataSourceContextHolder.remove();
        }
    }

    @Test
    public void testAccountInfo(){
        try {
            // 1.設(shè)置需要切換的數(shù)據(jù)源
            DataSourceContextHolder.set("db2");
            // 2.執(zhí)行插入操作
            accountInfoService.insert(new AccountInfo(1, "中國銀行"));
        } finally {
            // 3.操作完成之后,移除本地線程緩存的數(shù)據(jù)源
            DataSourceContextHolder.remove();
        }
    }
}

運(yùn)行單元測試,輸出結(jié)果如下:

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ff6efdc]
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@78226c36] will be managed by Spring
==>  Preparing: insert into tb_user_info(id, user_name) values(?, ?) 
==> Parameters: 1(Integer), 張三(String)
<==    Updates: 1
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ff6efdc]

...

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c9e07c6]
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2b10ace9] will be managed by Spring
==>  Preparing: insert into tb_account_info(id, account_name) values(?, ?) 
==> Parameters: 1(Integer), 中國銀行(String)
<==    Updates: 1
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c9e07c6]

從日志打印上可以清晰的看到,數(shù)據(jù)被成功的插入到對應(yīng)的數(shù)據(jù)庫中。

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

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

實(shí)現(xiàn)過程如下。

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

首先,定義一個數(shù)據(jù)源注解來實(shí)現(xiàn)數(shù)據(jù)源的切換,同時配置一個默認(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";
}

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

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

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();
        }
    }
}

這里有一個很重要的配置就是@Order(1),表示代理類會優(yōu)先被執(zhí)行,值越低優(yōu)先級越高。

當(dāng)@DbSource和@Transactional注解同時應(yīng)用在一個方法上時,如果不指定代理類的順序,當(dāng)調(diào)用方法的時候,會出現(xiàn)事務(wù)異常的問題。

原因在于:@Transactional注解所在的代理類,默認(rèn)優(yōu)先級是Integer.MAX,也就是最后被執(zhí)行;當(dāng)自定義的代理類沒有配置優(yōu)先級時,同樣默認(rèn)值也是Integer.MAX,但是自定義的會排在后面執(zhí)行,此時當(dāng)調(diào)用標(biāo)注事務(wù)注解的方法時,事務(wù)代理類會先執(zhí)行,但是數(shù)據(jù)源并沒有被設(shè)置,會導(dǎo)致事務(wù)控制異常,這一點(diǎn)需要特別注意。

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

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

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

@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);
    }
}

2.5.4、編寫單元測試

最后,編寫一個單元測試方法,驗(yàn)證代碼的正確性,代碼示例如下:

package com.example.dynamic.datasource.junit;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DynamicDataSourceJunit {

    @Autowired
    private AccountInfoService accountInfoService;

    @Autowired
    private UserInfoService userInfoService;

    @Test
    public void test(){
        // 新增用戶
        userInfoService.add(new UserInfo(1, "張三"));

        // 新增賬戶數(shù)據(jù)
        accountInfoService.add(new AccountInfo(1, "中國銀行"));
    }
}

日志輸出結(jié)果如下:

圖片圖片

可以看到,數(shù)據(jù)被正確的插入到對應(yīng)的數(shù)據(jù)庫中,與預(yù)期一致。

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

三、動態(tài)數(shù)據(jù)源配置介紹

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

能不能改成動態(tài)的加載數(shù)據(jù)源呢,答案是可以的!

下面我們一起來看看相關(guān)的具體實(shí)現(xiàn)方式。

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

首先,我們需要準(zhǔn)備一張數(shù)據(jù)源配置表。新建一個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ù)源的查詢。

INSERT INTO `tb_db_info` (`id`, `db_name`, `db_url`, `driver_class_name`, `username`, `password`)
VALUES
  (1, 'db1', 'jdbc:mysql://localhost:3306/db_test_1', 'com.mysql.jdbc.Driver', 'root', 'root'),
  (2, 'db2', 'jdbc:mysql://localhost:3306/db_test_2', 'com.mysql.jdbc.Driver', 'root', 'root');

3.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

3.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ū)動
     */
    private String driverClassName;

    /**
     * 數(shù)據(jù)庫用戶名
     */
    private String username;

    /**
     * 數(shù)據(jù)庫密碼
     */
    private String password;

    // set、get方法等...
}
public interface DbInfoMapper {

    List<DbInfo> findAll();
}
<?xml versinotallow="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>

3.4、修改動態(tài)數(shù)據(jù)源服務(wù)類

對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對象
            super.afterPropertiesSet();
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

3.5、修改動態(tài)數(shù)據(jù)源配置類

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

@Configuration
publicclass DataSourceConfig {

    @Autowired
    private DataSourceProperties basicProperties;

    /**
     * 注入動態(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);
        // 注入動態(tài)數(shù)據(jù)源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 設(shè)置默認(rèn)數(shù)據(jù)源
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
        // 設(shè)置動態(tài)數(shù)據(jù)源集
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }
}

3.6、配置啟動時加載數(shù)據(jù)源服務(wù)類

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

@Component
publicclass LoadDataSourceRunner implements CommandLineRunner {

    @Autowired
    private DbInfoMapper dbInfoMapper;

    @Autowired
    private DynamicDataSource dynamicDataSource;

    @Override
    public void run(String... args) {
        List<DbInfo> dbList = dbInfoMapper.findAll();
        if(!CollectionUtils.isEmpty(dbList)){
            dynamicDataSource.loadDataSources(dbList);
        }
    }
}

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

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

package com.example.dynamic.datasource;

@MapperScan("com.example.dynamic.datasource.mapper")
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3.8、代碼測試

最后,重新運(yùn)行單元測試方法,輸出結(jié)果如下:

圖片圖片

從日志上可以清晰的看到,運(yùn)行結(jié)果與預(yù)期一致!

四、小結(jié)

本文主要圍繞利用 Spring Boot 來實(shí)現(xiàn)動態(tài)數(shù)據(jù)源的加載,進(jìn)行一次知識的整合和總結(jié),如果描述不對的地方,歡迎大家留言指出!

五、參考

1.https://www.baeldung.com/spring-boot-configure-multiple-datasources

2.https://cloud.tencent.com/developer/article/2370197

責(zé)任編輯:武曉燕 來源: 潘志的技術(shù)筆記
相關(guān)推薦

2023-12-13 12:20:36

SpringMySQL數(shù)據(jù)源

2020-12-31 07:55:33

spring bootMybatis數(shù)據(jù)庫

2023-10-18 15:25:29

數(shù)據(jù)源數(shù)據(jù)庫

2022-05-18 12:04:19

Mybatis數(shù)據(jù)源Spring

2022-05-10 10:43:35

數(shù)據(jù)源動態(tài)切換Spring

2025-04-17 03:33:00

SpringSQL動態(tài)查詢

2024-03-28 09:46:50

2020-11-24 09:56:12

數(shù)據(jù)源讀寫分離

2025-03-11 00:55:00

Spring停機(jī)安全

2023-02-06 14:44:00

嚴(yán)選數(shù)據(jù)源DB

2024-08-12 10:13:01

2020-03-13 14:05:14

SpringBoot+數(shù)據(jù)源Java

2009-08-14 10:26:27

ibatis多數(shù)據(jù)源

2021-09-15 16:20:02

Spring BootFilterJava

2023-01-04 09:33:31

SpringBootMybatis

2021-03-10 19:01:02

SQL數(shù)據(jù)源

2012-06-17 13:04:45

2024-08-02 09:15:22

Spring捕捉格式

2023-09-07 08:39:39

copy屬性數(shù)據(jù)源

2017-09-04 14:52:51

Tomcat線程數(shù)據(jù)源
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號