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 动态数据源切换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java JConsole远程连接配置案例详解

    Java JConsole远程连接配置案例详解

    这篇文章主要介绍了Java JConsole远程连接配置案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • java 使用poi动态导出的操作

    java 使用poi动态导出的操作

    这篇文章主要介绍了java 使用poi动态导出的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 程序猿必须要掌握的多线程安全问题之锁策略详解

    程序猿必须要掌握的多线程安全问题之锁策略详解

    在笔者面试过程时,经常会被问到各种各样的锁,如乐观锁、读写锁等等,非常繁多,在此做一个总结,介绍的内容如下,需要的朋友可以参考下
    2021-06-06
  • 详解Java中如何使用日志库在代码中添加日志

    详解Java中如何使用日志库在代码中添加日志

    这篇文章主要为大家介绍了Java中如何使用日志库在代码中添加日志详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • Java实现随机验证码具体代码

    Java实现随机验证码具体代码

    这篇文章主要为大家详细介绍了Java实现随机验证码具体代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • Java享元设计模式优化对象创建提高性能和效率

    Java享元设计模式优化对象创建提高性能和效率

    Java享元设计模式通过共享可重用的对象,减少了系统中对象的数量,优化了对象的创建和管理,提高了性能和效率。它是一种经典的设计模式,适用于需要处理大量相似对象的应用程序
    2023-04-04
  • SpringBoot整合spring-data-jpa的方法

    SpringBoot整合spring-data-jpa的方法

    这篇文章主要介绍了SpringBoot整合spring-data-jpa的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • Java实现PDF文件的分割与加密功能

    Java实现PDF文件的分割与加密功能

    这篇文章主要为大家分享了如何利用Java语言实现PDF文件的分割与加密以及封面图的生成,文中的示例代码简洁易懂,感兴趣的可以了解一下
    2022-04-04
  • Java 集合中的类关于线程安全

    Java 集合中的类关于线程安全

    这篇文章主要介绍了Java 集合中的类关于线程安全的相关资料,需要的朋友可以参考下
    2017-01-01
  • MyBatis Xml映射文件之字符串替换方式

    MyBatis Xml映射文件之字符串替换方式

    这篇文章主要介绍了MyBatis Xml映射文件之字符串替换方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11

最新评论