SpringBoot实现动态数据源切换的项目实践

 更新时间:2024年04月12日 10:39:22   作者:拥抱AI  
在实际开发过程中,我们经常遇到需要同时操作多个数据源的情况,本文主要介绍了SpringBoot实现动态数据源切换的项目实践,具有一定的参考价值,感兴趣的可以了解一下

本文将介绍如何在 Spring Boot 应用中实现动态数据源切换,包括具体实现步骤和示例代码。通过本文的学习,你将能够轻松应对多种数据源切换的场景,提高应用程序的灵活性和可扩展性。

一. 引言

在实际开发过程中,我们经常遇到需要同时操作多个数据源的情况。例如,可能需要从不同的数据库中读取数据,或者根据业务需求将数据写入不同的数据库。在这种情况下,动态数据源切换就变得尤为重要。Spring Boot 提供了强大的数据源配置功能,使得动态数据源切换变得相对简单。本文将详细介绍如何在 Spring Boot 应用中实现动态数据源切换。

二. 准备工作

在开始实现动态数据源切换之前,我们需要做一些准备工作:

1.创建 Spring Boot 项目

首先,我们需要创建一个 Spring Boot 项目。可以使用 Spring Initializr(https://start.spring.io/)快速生成项目骨架。在创建项目时,选择合适的 JDK 版本、项目构建工具(如 Maven 或 Gradle)以及项目元数据(如项目名称、描述、包名等)。

2.添加依赖

在项目的 pom.xml 文件中添加以下依赖:

<dependencies>
    <!-- Spring Boot Web 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Boot 数据源依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- 数据库驱动依赖,以 MySQL 为例 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

三. 实现动态数据源切换

接下来,我们将介绍如何实现动态数据源切换。主要分为以下几个步骤:

1.配置数据源

在 application.properties 或 application.yml 文件中配置多个数据源,如下所示:

spring:
  datasource:
    primary:
      url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver
    secondary:
      url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

2.创建数据源配置类

创建一个数据源配置类,用于生成 DataSource 对象。这里我们使用 Java 配置的方式,如下所示:

@Configuration
public class DynamicDataSourceConfig {
    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }
}

3.创建动态数据源路由

创建一个动态数据源路由类,用于根据不同的条件切换不同的数据源。如下所示:

public class DynamicDataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
    public static void setDataSourceType(String dataSourceType) {
        CONTEXT_HOLDER.set(dataSourceType);
    }
    public static String getDataSourceType() {
        return CONTEXT_HOLDER.get();
    }
    public static void clearDataSourceType() {
        CONTEXT_HOLDER.remove();
    }
}

4.配置数据源路由

在 application.properties 或 application.yml 文件中配置数据源路由,如下所示:

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    dynamic:
      primary: primaryDataSource
      secondary: secondaryDataSource

5.创建数据源切换切面

创建一个切面类,用于在方法执行前切换数据源,在方法执行后恢复数据源。如下所示:

@Aspect
@Component
public class DynamicDataSourceAspect {
    @Before("@annotation(TargetDataSource)")
    public void switchDataSource(JoinPoint point) {
        // 获取方法上的注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        TargetDataSource ds = method.getAnnotation(TargetDataSource.class);
        // 判断注解是否为空
        if (ds == null) {
            return;
        }
        // 切换数据源
        DynamicDataSourceContextHolder.setDataSourceType(ds.name());
    }
    @After("@annotation(TargetDataSource)")
    public void restoreDataSource(JoinPoint point) {
        // 获取方法上的注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        TargetDataSource ds = method.getAnnotation(TargetDataSource.class);
        // 判断注解是否为空
        if (ds == null) {
            return;
        }
        // 恢复数据源
        DynamicDataSourceContextHolder.clearDataSourceType();
    }
}

6.创建自定义注解

创建一个自定义注解,用于标记需要切换数据源的方法。如下所示:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetDataSource {
    String name();
}

7.使用自定义注解

在需要切换数据源的方法上使用自定义注解,如下所示:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    @TargetDataSource(name = "primary")
    public List<User> findUsersFromPrimary() {
        return userMapper.findAll();
    }
    @TargetDataSource(name = "secondary")
    public List<User> findUsersFromSecondary() {
        return userMapper.findAll();
    }
}

四. 测试动态数据源切换

为了验证我们的动态数据源切换是否生效,我们可以编写一些测试用例来模拟不同的数据源切换场景。
首先,我们需要创建一个简单的实体类和对应的仓库接口:

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    // 省略 getter 和 setter
}
public interface UserRepository extends JpaRepository<User, Long> {
}

然后,我们可以编写一个测试类来测试动态数据源的切换:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
    @Autowired
    private UserService userService;
    @Test
    public void testDynamicDataSource() {
        List<User> usersFromPrimary = userService.findUsersFromPrimary();
        List<User> usersFromSecondary = userService.findUsersFromSecondary();
        
        // 假设我们期望从主数据源和从数据源分别查询到不同的用户列表
        assertNotNull(usersFromPrimary);
        assertNotNull(usersFromSecondary);
        assertNotEquals(usersFromPrimary, usersFromSecondary);
    }
}

在这个测试类中,我们注入了 UserService,并调用了两个方法来分别从主数据源和从数据源查询用户列表。我们使用了 assertNotNull 和 assertNotEquals 来验证查询结果,确保我们从两个不同的数据源获取到了不同的数据。

五. 注意事项

在实现动态数据源切换时,有几个注意事项需要牢记:

  • 确保所有的数据源配置都是正确的,包括URL、用户名、密码和驱动类名。
  • 在切换数据源时,要确保在操作完成后恢复到默认数据源,以避免影响其他业务逻辑。
  • 在生产环境中,要考虑数据源切换的性能影响,尤其是在高并发场景下。
  • 动态数据源切换可能会增加代码的复杂性,因此要谨慎使用,确保它带来的好处大于维护成本。

六. 总结

本文详细介绍了在 Spring Boot 应用中实现动态数据源切换的方法。通过配置多个数据源、创建数据源路由、使用切面编程和自定义注解,我们可以在运行时根据业务需求灵活地切换数据源。这种方法特别适合于需要同时访问多个数据库或数据源的应用场景。虽然动态数据源切换增加了系统的复杂性,但正确使用它可以为应用带来更高的灵活性和可扩展性。

到此这篇关于SpringBoot实现动态数据源切换的项目实践的文章就介绍到这了,更多相关SpringBoot 动态数据源切换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring MVC中使用Controller如何进行重定向

    Spring MVC中使用Controller如何进行重定向

    这篇文章主要介绍了Spring MVC中使用Controller如何进行重定向操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java8 Stream collect(Collectors.toMap())的使用

    Java8 Stream collect(Collectors.toMap())的使用

    这篇文章主要介绍了Java8 Stream collect(Collectors.toMap())的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • Java实现简单抽奖功能界面

    Java实现简单抽奖功能界面

    这篇文章主要为大家详细介绍了Java实现简单抽奖功能界面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • 详解PowerDesigner之CDM、PDM、SQL之间转换

    详解PowerDesigner之CDM、PDM、SQL之间转换

    这篇文章主要介绍了详解PowerDesigner之CDM、PDM、SQL之间转换的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-10-10
  • 浅谈java 中文件的读取File、以及相对路径的问题

    浅谈java 中文件的读取File、以及相对路径的问题

    今天小编就为大家分享一篇浅谈java 中文件的读取File、以及相对路径的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • java ZipFile如何将多级目录压缩

    java ZipFile如何将多级目录压缩

    这篇文章主要介绍了java ZipFile如何将多级目录压缩问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • JAVA中三种常用的循环语句详解

    JAVA中三种常用的循环语句详解

    这篇文章主要介绍了JAVA中三种常用的循环语句详解,包括格式和执行流程,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • 使用Java计算屏幕的PPI的方法详解

    使用Java计算屏幕的PPI的方法详解

    在现代电子设备中,屏幕的分辨率和显示效果是用户非常关注的一个指标,PPI(Pixels Per Inch,每英寸像素数)是衡量屏幕显示精度的重要参数之一,PPI越高,屏幕显示的图像越细腻,视觉效果越好,本文将详细介绍PPI的概念、计算方法,并通过Java代码实现PPI的计算
    2025-02-02
  • Java模拟计算机的整数乘积计算功能示例

    Java模拟计算机的整数乘积计算功能示例

    这篇文章主要介绍了Java模拟计算机的整数乘积计算功能,简单分析了计算机数值进制转换与通过位移进行乘积计算的原理,并结合具体实例给出了java模拟计算机成绩运算的相关操作技巧,需要的朋友可以参考下
    2017-09-09
  • jdk21安装后无jre文件该如何解决

    jdk21安装后无jre文件该如何解决

    java开发少不了安装jdk,下面这篇文章主要给大家介绍了关于jdk21安装后无jre文件该如何解决的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2024-05-05

最新评论