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

Spring Boot + MyBatis-Plus 實現(xiàn) MySQL 主從復(fù)制動態(tài)數(shù)據(jù)源切換

開發(fā) 前端
AbstractRoutingDataSource 是 Spring Framework 提供的一個抽象數(shù)據(jù)源類,用于實現(xiàn)動態(tài)數(shù)據(jù)源切換。它允許應(yīng)用程序在運(yùn)行時動態(tài)地切換到不同的數(shù)據(jù)源,從而支持多數(shù)據(jù)源的場景,比如數(shù)據(jù)庫讀寫分離、主從復(fù)制等

MySQL 主從復(fù)制是一種常見的數(shù)據(jù)庫架構(gòu),它可以提高數(shù)據(jù)庫的性能和可用性。動態(tài)數(shù)據(jù)源切換則可以根據(jù)業(yè)務(wù)需求,在不同場景下使用不同的數(shù)據(jù)源,比如在讀多寫少的場景下,可以通過切換到從庫來分擔(dān)主庫的壓力。

在本文中,我們將介紹如何在 Spring Boot 中實現(xiàn) MySQL 主從復(fù)制和動態(tài)數(shù)據(jù)源切換,使用 MyBatis-Plus 進(jìn)行數(shù)據(jù)庫操作

#代碼地址
https://github.com/bangbangzhou/spring-boot-dynamic-master-slave.git

今日內(nèi)容介紹,大約花費(fèi)19分鐘

圖片圖片

那么接下來我們開始項目實現(xiàn),項目結(jié)構(gòu)如下

圖片圖片

1.引入依賴

在項目的的pom.xml文件中引入Spring Boot和MyBatis-Plus的相關(guān)依賴

<?xml versinotallow="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.7.15</version>
    </parent>

    <groupId>com.zbbmeta</groupId>
    <artifactId>spring-boot-dynamic-master-slave</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2. 配置數(shù)據(jù)源

在application.yml文件中配置主從數(shù)據(jù)源信息。注意這里我們要搭建主從數(shù)據(jù)庫,只是在一個mysql實例中創(chuàng)建兩個庫,里面存在相同表

server:
  port: 8082

spring:
  datasource:
    master:
      username: root
      password: root
      url: jdbc:mysql://localhost:3306/shiro_db?useUnicode=true&characterEncoding=utf8
      driver-class-name: com.mysql.cj.jdbc.Driver
    slave:
      username: root
      password: root
      url: jdbc:mysql://localhost:3306/backend_db?useUnicode=true&characterEncoding=utf8
      driver-class-name: com.mysql.cj.jdbc.Driver


mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml

3. 創(chuàng)建DatabaseType 枚舉類型

創(chuàng)建DatabaseType 枚舉類型,用于切換數(shù)據(jù)源時,確定連接的是哪個數(shù)據(jù)源

在com.zbbmeta.config包下創(chuàng)建DatabaseType枚舉類型

// 定義一個枚舉類型 DatabaseType,表示系統(tǒng)中的數(shù)據(jù)庫類型
public enum DatabaseType {
    MASTER,  // 主數(shù)據(jù)庫類型
    SLAVE    // 從數(shù)據(jù)庫類型
}

4. 配置數(shù)據(jù)源上下文

在com.zbbmeta.holder包下創(chuàng)建一個DataSourceContextHolder類用于保存和獲取當(dāng)前線程使用的數(shù)據(jù)源類型

public class DatabaseContextHolder {

    private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();

    public static void setDatabaseType(DatabaseType databaseType) {
        contextHolder.set(databaseType);
    }

    public static DatabaseType getDatabaseType() {
        return contextHolder.get();
    }

    public static void clearDatabaseType() {
        contextHolder.remove();
    }
}

5. 配置動態(tài)數(shù)據(jù)源

我們創(chuàng)建了一個 DynamicDataSource 類,繼承 AbstractRoutingDataSource,用于實現(xiàn)動態(tài)數(shù)據(jù)源的切換。

AbstractRoutingDataSource 是 Spring Framework 提供的一個抽象數(shù)據(jù)源類,用于實現(xiàn)動態(tài)數(shù)據(jù)源切換。它允許應(yīng)用程序在運(yùn)行時動態(tài)地切換到不同的數(shù)據(jù)源,從而支持多數(shù)據(jù)源的場景,比如數(shù)據(jù)庫讀寫分離、主從復(fù)制等

AbstractRoutingDataSource介紹:

  • 動態(tài)數(shù)據(jù)源切換:AbstractRoutingDataSource 的核心思想是根據(jù)某個鍵值(lookup key)來決定使用哪個具體的數(shù)據(jù)源。這個鍵值是通過 determineCurrentLookupKey() 方法提供
  • 抽象類:AbstractRoutingDataSource 是一個抽象類,它提供了模板方法 determineCurrentLookupKey(),需要由子類實現(xiàn)
  • 實現(xiàn) javax.sql.DataSource 接口:AbstractRoutingDataSource 實現(xiàn)了 javax.sql.DataSource 接口,因此可以像常規(guī)數(shù)據(jù)源一樣被用于與數(shù)據(jù)庫的交互。
  • 在 Spring 配置中使用:在 Spring 的配置中,我們可以將 AbstractRoutingDataSource 配置為數(shù)據(jù)源 bean,并將真實的數(shù)據(jù)源作為其目標(biāo)數(shù)據(jù)源。在需要切換數(shù)據(jù)源的時候,調(diào)用 determineCurrentLookupKey() 方法,它將返回用于切換數(shù)據(jù)源的鍵值。

在com.zbbmeta.config包下創(chuàng)建DynamicDataSource類

public class DynamicDataSource extends AbstractRoutingDataSource {

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

DynamicDataSource類中重寫determineCurrentLookupKey()方法:在這個方法中,我們通過調(diào)用 DataSourceContextHolder.getDataSourceType() 來獲取當(dāng)前線程持有的數(shù)據(jù)源類型。這個方法的返回值將被用作數(shù)據(jù)源的 lookup key,從而實現(xiàn)動態(tài)切換。

6. 添加DataSource注解類

在·com.zbbmeta.annotation包下創(chuàng)建DataSource注解類,這是一個自定義注解,用于標(biāo)記在類或方法上,以指定數(shù)據(jù)源的類型。下面是對這段代碼的注解說明

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    DatabaseType type() default DatabaseType.SLAVE;

}

注解說明:

  • @interface DataSource:這是一個注解的聲明,用于創(chuàng)建名為 DataSource 的自定義注解。
  • @Target({ElementType.METHOD, ElementType.TYPE}):@Target 注解表示此注解可以用于類和方法。在這里,DataSource 注解可以標(biāo)注在類和方法上。
  • @Retention(RetentionPolicy.RUNTIME):@Retention 注解表示這個注解的生命周期,即在運(yùn)行時仍然可用。這是因為我們希望在運(yùn)行時通過反射獲取注解信息。
  • DatabaseType type() default DatabaseType.SLAVE:這是 DataSource 注解的一個成員變量。它是一個枚舉類型的變量,表示數(shù)據(jù)庫類型,默認(rèn)值為 SLAVE。通過這個成員變量,我們可以在使用 DataSource 注解時指定使用的數(shù)據(jù)源類型

7. 配置數(shù)據(jù)源切換切面

在com.zbbmeta.aspect包下創(chuàng)建一個切面類DataSourceAspect,用于在執(zhí)行數(shù)據(jù)庫操作前動態(tài)切換數(shù)據(jù)源。

@Aspect
@Component
@EnableAspectJAutoProxy
public class DataSourceAspect {
// 定義切點(diǎn),匹配使用了 @DataSource 注解的方法
    @Pointcut("@annotation(com.zbbmeta.annotation.DataSource)")
    public void dataSourcePointCut() {}

    // 環(huán)繞通知,在方法執(zhí)行前后切換數(shù)據(jù)源
    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        // 獲取方法上的 @DataSource 注解
        DataSource dataSource = method.getAnnotation(DataSource.class);
        if (dataSource != null) {
            // 切換數(shù)據(jù)源類型
            DatabaseContextHolder.setDatabaseType(dataSource.type());
        }

        try {
            // 執(zhí)行目標(biāo)方法
            return point.proceed();
        } finally {
            // 清除數(shù)據(jù)源類型,確保線程安全
            DatabaseContextHolder.clearDatabaseType();
        }
    }
}

8. 創(chuàng)建DataSourceConfig

在com.zbbmeta.config包下創(chuàng)建DataSourceConfig,用于配置主從兩個數(shù)據(jù)源

@Configuration
@Data
public class DataSourceConfig {
    @Value("${spring.datasource.master.url}")
    private String dbUrl;
    @Value("${spring.datasource.master.username}")
    private String username;
    @Value("${spring.datasource.master.password}")
    private String password;
    @Value("${spring.datasource.master.driver-class-name}")
    private String driverClassName;


    @Value("${spring.datasource.slave.url}")
    private String slaveDbUrl;
    @Value("${spring.datasource.slave.username}")
    private String slaveUsername;
    @Value("${spring.datasource.slave.password}")
    private String slavePassword;
    @Value("${spring.datasource.slave.driver-class-name}")
    private String slaveDriverClassName;


    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create()
                .driverClassName(driverClassName)
                .url(dbUrl)
                .username(username)
                .password(password)
                .build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {

        return DataSourceBuilder.create()
                .driverClassName(slaveDriverClassName)
                .url(slaveDbUrl)
                .username(slaveUsername)
                .password(slavePassword)
                .build();

    }
}

9 創(chuàng)建DataSourceConfig

在com.zbbmeta.config包下創(chuàng)建DynamicDataSourceConfig類中配置MyBatis-Plus的相關(guān)內(nèi)容。

@Configuration
@MapperScan("com.zbbmeta.mapper")
public class DynamicDataSourceConfig {
    @Autowired
    private DataSource masterDataSource;

    @Autowired
    private DataSource slaveDataSource;

    // 配置動態(tài)數(shù)據(jù)源
    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseType.MASTER, masterDataSource);
        targetDataSources.put(DatabaseType.SLAVE, slaveDataSource);

        DynamicRoutingDataSource dynamicDataSource = new DynamicRoutingDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 設(shè)置默認(rèn)數(shù)據(jù)源
        return dynamicDataSource;
    }

    // 配置 MyBatis 的 SqlSessionFactory
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dynamicDataSource) throws Exception {
        MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dynamicDataSource);

        // 設(shè)置要掃描的 mapper 接口和 XML 文件路徑
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        sessionFactoryBean.setTypeAliasesPackage("com.zbbmeta.entity");  // 設(shè)置實體類包路徑

        return sessionFactoryBean.getObject();
    }

    // 配置 MyBatis 的 SqlSessionTemplate
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

10. 測試

使用MybatisX生成代碼,并且創(chuàng)建com.zbbmeta.controller包下創(chuàng)建TutorialController類,并且在需要切換數(shù)據(jù)源的方法上使用 @DataSource 注解,切面將根據(jù)該注解的配置在方法執(zhí)行前后進(jìn)行數(shù)據(jù)源切換。

圖片圖片

圖片圖片

@RestController
public class TutorialController {


    @Autowired
    private TutorialService tutorialService;


    @DataSource
    @GetMapping("/list")
    public List<Tutorial> list(){
        return tutorialService.list();

    }

    @DataSource(type = DatabaseType.MASTER)
    @GetMapping("/create")
    public Boolean create(){

        Tutorial tutorial = new Tutorial();
        tutorial.setTitle("master");
        tutorial.setDescription("master");

        return tutorialService.save(tutorial);
    }
}

使用POSTMAN發(fā)送請求

http://localhost:8082/list

http://localhost:8082/create
#代碼地址
https://github.com/bangbangzhou/spring-boot-dynamic-master-slave.git

責(zé)任編輯:武曉燕 來源: springboot葵花寶典
相關(guān)推薦

2023-06-07 08:08:37

MybatisSpringBoot

2025-01-17 09:11:51

2024-07-31 09:56:20

2020-12-31 07:55:33

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

2025-02-10 10:55:16

2025-01-15 15:47:36

2024-03-01 18:33:59

MySQL節(jié)點(diǎn)數(shù)據(jù)

2021-06-08 07:48:27

MySQL主從配置

2024-12-20 16:49:15

MyBatis開發(fā)代碼

2023-01-04 09:33:31

SpringBootMybatis

2024-07-04 08:00:24

2023-03-19 22:38:12

邏輯復(fù)制PostgreSQL

2024-11-15 15:27:09

2025-04-07 00:00:00

MySQL數(shù)據(jù)庫服務(wù)器

2024-07-15 09:14:03

MySQL主從復(fù)制

2023-03-19 11:53:27

2022-12-20 08:46:41

MySQL主從復(fù)制

2022-05-10 10:43:35

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

2021-09-08 10:23:08

讀寫分離Java數(shù)據(jù)庫

2023-10-18 15:25:29

數(shù)據(jù)源數(shù)據(jù)庫
點(diǎn)贊
收藏

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