当前位置: 首页 > news >正文

Spring Boot 动态数据源实操指南

在实际开发中,我们经常会遇到需要动态切换数据源的场景,比如多租户系统、读写分离、分库分表等。Spring Boot 提供了灵活的配置方式,结合 AbstractRoutingDataSource 可以轻松实现动态数据源切换。本文将带你一步步实现 Spring Boot 动态数据源的配置与使用。


一、动态数据源的原理

Spring Boot 的动态数据源核心原理是通过 AbstractRoutingDataSource 实现数据源的路由。AbstractRoutingDataSource 是一个抽象类,它允许我们根据当前的上下文(如线程局部变量)动态选择目标数据源。

核心流程:

  1. 定义多个数据源(如主库、从库)。
  2. 继承 AbstractRoutingDataSource,实现 determineCurrentLookupKey() 方法,返回当前线程需要使用的数据源标识。
  3. 通过 AOP 或手动切换的方式,动态设置数据源标识。

二、实现步骤

1. 创建 Spring Boot 项目

使用 Spring Initializr 创建一个 Spring Boot 项目,添加以下依赖:

  • Spring Web
  • Spring Data JPA
  • MySQL Driver
  • HikariCP(连接池)
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId></dependency>
</dependencies>

2. 配置多数据源

application.yml 中配置多个数据源,例如主库和从库:

spring:datasource:master:jdbc-url: jdbc:mysql://localhost:3306/master_dbusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driverslave:jdbc-url: jdbc:mysql://localhost:3306/slave_dbusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver

3. 创建数据源配置类

通过 Java 配置类加载多个数据源。

@Configuration
public class DataSourceConfig {@Bean(name = "masterDataSource")@ConfigurationProperties(prefix = "spring.datasource.master")public DataSource masterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}
}

4. 实现动态数据源路由

创建 DynamicDataSource 类继承 AbstractRoutingDataSource,并实现 determineCurrentLookupKey() 方法。

public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSourceKey();}
}

5. 创建数据源上下文管理类

使用 ThreadLocal 保存当前线程的数据源标识。

public class DataSourceContextHolder {private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();public static void setDataSourceKey(String key) {contextHolder.set(key);}public static String getDataSourceKey() {return contextHolder.get();}public static void clearDataSourceKey() {contextHolder.remove();}
}

6. 配置动态数据源

将多个数据源注入到 DynamicDataSource 中。

@Configuration
public class DynamicDataSourceConfig {@Beanpublic DataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,@Qualifier("slaveDataSource") DataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("master", masterDataSource);targetDataSources.put("slave", slaveDataSource);DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 默认数据源dynamicDataSource.setTargetDataSources(targetDataSources);return dynamicDataSource;}
}

7. 配置事务管理器

由于动态数据源的切换会影响事务管理,需要配置一个支持动态数据源的事务管理器。

@Bean
public PlatformTransactionManager transactionManager(DataSource dynamicDataSource) {return new DataSourceTransactionManager(dynamicDataSource);
}

8. 使用 AOP 动态切换数据源

通过 AOP 在方法执行前切换数据源。

@Aspect
@Component
public class DataSourceAspect {@Before("@annotation(com.example.demo.annotation.Master)")public void setMasterDataSource() {DataSourceContextHolder.setDataSourceKey("master");}@Before("@annotation(com.example.demo.annotation.Slave)")public void setSlaveDataSource() {DataSourceContextHolder.setDataSourceKey("slave");}@After("@annotation(com.example.demo.annotation.Master) || @annotation(com.example.demo.annotation.Slave)")public void clearDataSource() {DataSourceContextHolder.clearDataSourceKey();}
}

9. 定义注解

为了方便切换数据源,定义两个注解:@Master@Slave

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

10. 测试动态数据源

在 Service 层使用注解切换数据源。

@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Masterpublic void addUser(User user) {userRepository.save(user);}@Slavepublic List<User> getUsers() {return userRepository.findAll();}
}

三、总结

通过以上步骤,我们实现了一个简单的 Spring Boot 动态数据源切换功能。核心点包括:

  1. 使用 AbstractRoutingDataSource 实现数据源路由。
  2. 通过 ThreadLocal 管理当前线程的数据源标识。
  3. 使用 AOP 和注解简化数据源切换。

动态数据源切换是一个非常实用的功能,适用于多租户、读写分离等场景。希望本文能帮助你更好地理解和应用 Spring Boot 动态数据源技术!

http://www.lryc.cn/news/537801.html

相关文章:

  • HBase高级技巧:解锁更强大的数据处理能力
  • 【进阶】JVM篇
  • DeepSeek官方推荐的AI集成系统
  • 【动态规划篇】:当回文串遇上动态规划--如何用二维DP“折叠”字符串?
  • JENKINS(全面)
  • Promise详解大全:介绍、九个方法使用和区别、返回值详解
  • 尚硅谷爬虫note004
  • Debezium系列之:时区转换器,时间戳字段转换到指定时区
  • ubuntu20.04声音设置
  • 如何设置Python爬虫的User-Agent?
  • 深度学习框架探秘|TensorFlow:AI 世界的万能钥匙
  • C++:高度平衡二叉搜索树(AVLTree) [数据结构]
  • 建筑兔零基础自学python记录18|实战人脸识别项目——视频检测07
  • 【MySQL数据库】Ubuntu下的mysql
  • [MySQL#1] database概述 常见的操作指令 MySQL架构 存储引擎
  • 1.从零开始学会Vue--{{基础指令}}
  • VS2022中.Net Api + Vue 从创建到发布到IIS
  • RFID技术在制造环节的应用与价值
  • (前端基础)HTML(一)
  • Linux文件管理:硬链接与软链接
  • pnpm, eslint, vue-router4, element-plus, pinia
  • 在软件产品从开发到上线过程中,不同阶段可能出现哪些问题,导致软件最终出现线上bug
  • Spring Boot中如何自定义Starter
  • 制作Ubuntu根文件
  • SpringBoot快速接入OpenAI大模型(JDK8)
  • UniApp 中制作一个横向滚动工具栏
  • react中如何获取真实的dom
  • 5G与物联网的协同发展:打造智能城市的未来
  • 【Qt】实现定期清理程序日志
  • git bisect 使用二分法查找引入错误的提交