Spring Boot 中动态数据源配置与使用详解

ops/2024/9/22 23:59:53/

Spring Boot 中动态数据源配置与使用详解

在现代应用中,处理多数据源是常见的需求。可能由于业务需要,或者为了实现读写分离,我们往往需要在同一个应用中配置多个数据源,并根据具体的操作选择不同的数据源。在 Spring Boot 中,这样的需求可以通过动态数据源来轻松实现。本篇博客将详细介绍如何在 Spring Boot 中配置和使用动态数据源,并演示如何切换到指定的数据源。

一、为什么要使用动态数据源?
  1. 业务隔离:在一些复杂的业务场景中,不同的模块可能需要连接不同的数据库。通过动态数据源配置,可以在同一个应用中隔离这些不同的数据库访问。

  2. 读写分离:为了提升系统的性能,通常会将读写操作分离到不同的数据库上。比如,将写操作放在主数据库,而读操作放在从数据库上。

  3. 数据库迁移:在系统迁移期间,可能需要在两个数据库之间切换,从而确保迁移的平稳进行。

二、Spring Boot 中的多数据源配置

我们将通过一个示例来介绍如何在 Spring Boot 中配置和使用动态数据源。假设我们有两个数据源,一个是 master,另一个是 adcontrolmaster 数据源主要用于主业务数据库,而 adcontrol 数据源用于广告控制的相关数据存储。

1. 数据源配置

首先,我们需要在 application.yml 文件中配置两个数据源。

datasource:dynamic:primary: master # 默认使用master库strict: false   # 不使用严格模式datasource:master:url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverhikari:connection-timeout: 30000max-lifetime: 1800000max-pool-size: 15min-idle: 5connection-test-query: select 1pool-name: YsxHikariCPadcontrol:url: jdbc:mysql://ip:3306/test2?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=falseusername: testpassword: testdriver-class-name: com.mysql.cj.jdbc.Driver

上述配置中,master 数据源是默认使用的数据源,而 adcontrol 数据源是备用的广告控制数据源。

2. 引入动态数据源依赖

为了让 Spring Boot 能够识别和使用这些动态数据源,我们需要引入动态数据源的依赖库。这里我们使用 dynamic-datasource-spring-boot-starter 这个开源库。

pom.xml 中添加如下依赖:

<dependency><groupId>com.github.dynamic-datasource</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.2.1</version> <!-- 确保使用合适的版本 -->
</dependency>
3. 配置动态数据源

通过 DynamicDataSource,我们可以在应用中灵活切换数据源。下面是一个简单的 DynamicDataSource 配置示例:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.dynamic.datasource.DynamicRoutingDataSource;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import java.util.HashMap;
import java.util.Map;@Configuration
public class DataSourceConfig {@Beanpublic DataSource dataSource() {DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();// 配置主数据源DataSource masterDataSource = DataSourceBuilder.create().url("jdbc:mysql://127.0.0.1:3306/test1?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false").username("root").password("123456").driverClassName("com.mysql.cj.jdbc.Driver").build();// 配置广告控制数据源DataSource adcontrolDataSource = DataSourceBuilder.create().url("jdbc:mysql://ip1:3306/test2?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false").username("test").password("test").driverClassName("com.mysql.cj.jdbc.Driver").build();// 将数据源放入MapMap<Object, Object> dataSourceMap = new HashMap<>();dataSourceMap.put("master", masterDataSource);dataSourceMap.put("adcontrol", adcontrolDataSource);dataSource.setDefaultTargetDataSource(masterDataSource);dataSource.setTargetDataSources(dataSourceMap);return dataSource;}
}
4. 使用 @DS 注解动态切换数据源

在服务层,我们可以通过 @DS 注解来指定当前方法应该使用哪个数据源。例如:

import com.github.dynamic.datasource.annotation.DS;
import org.springframework.stereotype.Service;@Service
public class MyService {@DS("adcontrol")public void handleAdControlLogic() {// 使用adcontrol数据源执行操作}@DS("master")public void handleMasterLogic() {// 使用master数据源执行操作}
}

通过 @DS 注解,我们可以在方法层面灵活切换数据源,确保不同的业务逻辑使用正确的数据库连接。

三、异常处理与回滚

在使用多个数据源时,处理好事务和异常非常重要。如果在一个事务内执行了多个数据源的操作,那么事务的管理和异常处理就变得尤为关键。

Spring 提供了全局事务管理器的支持,可以配置为管理多个数据源的事务。但是在使用 dynamic-datasource 时,要特别注意确保在同一个事务中操作的多个数据源能够正确地提交或回滚。

例如:

import org.springframework.transaction.annotation.Transactional;@Service
public class MyService {@Transactional@DS("master")public void processTransaction() {try {// 操作master数据库handleMasterLogic();// 切换到adcontrol数据源handleAdControlLogic();} catch (Exception e) {// 处理异常,可能需要回滚事务throw new RuntimeException("事务失败,进行回滚", e);}}@DS("adcontrol")public void handleAdControlLogic() {// 操作adcontrol数据库}@DS("master")public void handleMasterLogic() {// 操作master数据库}
}

在上面的代码中,如果 handleAdControlLogic 方法抛出了异常,那么整个事务将被回滚。

四、常见问题与解决方案
  1. 数据源切换失败

    • 确保 @DS 注解指向的名称与配置中的数据源名称完全一致。
    • 检查 DynamicDataSource 是否正确配置。
  2. 事务回滚失败

    • 确保在同一个事务中使用的所有数据源都支持事务管理。
    • 使用 @Transactional 注解来管理事务。
  3. 性能问题

    • 动态数据源切换可能会带来额外的性能开销。可以考虑使用连接池优化数据库连接管理。
  4. 无法连接数据库

    • 检查数据库连接配置,确保 urlusernamepassword 等参数正确。
    • 检查数据库服务器是否可达。
五、总结

通过动态数据源配置,Spring Boot 应用可以轻松应对多数据源的复杂需求。无论是业务隔离、读写分离,还是数据库迁移,动态数据源都能够提供灵活且高效的解决方案。

在实际应用中,合理规划和使用多数据源,可以显著提升系统的可扩展性和可靠性。在实现过程中,需要特别注意事务管理和异常处理,以确保数据的一致性和完整性。

通过本文的介绍,相信你已经掌握了在 Spring Boot 中配置和使用动态数据源的基本方法。在实际项目中,可以根据业务需求,进一步优化和扩展动态数据源的使用。希望本文能对你有所帮助。


http://www.ppmy.cn/ops/98003.html

相关文章

20. 表示数值的字符串

comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9820.%20%E8%A1%A8%E7%A4%BA%E6%95%B0%E5%80%BC%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2/README.md [面试题 20. 表示数值的字符串]逻辑题(https://leetc…

Camera调试ISP TimeOut问题,会是什么原因

在MT6572平臺上面調試camera 遇到isp timeout 硬體訊號都正常&#xff01;這是一些LOG K_ISP ERR: Timeout: Clear(1), IrqStatus(0x00000080), WaitStatus(0x00000001), Timeout(2000) K_ISP INF: 而我看MTK FAQ08102 裏這麼說 [FAQ08102][Camera Drv]Mt6572黑屏&#xff0c…

Linux网络编程2(理解局域网)

前面的一篇文章&#xff0c;我们简单地了解了网络的发展过程&#xff0c;并且简单的介绍了网络的一些基本术语&#xff0c;这篇文章&#xff0c;我们来详细的了解一下局域网的内容&#xff0c;相信看完这篇文章&#xff0c;大家能够对局域网有清晰的认识。 教科书一般是按照五层…

HCIA云计算实验-2-网络基础实验

HCIA云计算-02-网络基础实验 实验内容&#xff1a; 交换机视图介绍交换机基础配置VLAN原理实验路由原理实验 vlan 介绍 VLAN(Virtual Local Area Network)即虚拟局域网&#xff0c;是将一个物理的 LAN 在逻辑上划分成多个广播域的通信技术。每个 VLAN 是一个广播域&#xf…

平衡二叉树、B树、B+树、红黑树解析

目录 有序二叉树平衡二叉树构造平衡二叉树RRLLRLLR 平衡二叉树的优缺点&#xff1a; 2-3-4树红黑树B树B树B树、B树、红黑树的应用 有序二叉树 关于有序二叉树的详解以及 J a v a Java Java代码实现详见&#xff1a;二叉排序树详解并通过Java代码实现。每个节点最多有两个孩子…

为什么Qt源码中要用d_ptr和q_ptr

为什么需要d_ptr和q_ptr Qt中的公有类中一般都会包含d_ptr这样一个私有类型的指针&#xff0c;指针指向该类对应的私有类&#xff0c;引入这个指针主要是为了解决二进制兼容的问题。q_ptr是和d_ptr配套的&#xff0c;后面会介绍到。 什么是二进制兼容 Qt作为一个第三方库&…

【安卓】解析XML格式数据

这里需要搭建一个Web服务器&#xff0c;在这个服务器上提供一段XML文本&#xff0c;然后在程序里去访问这个服务器&#xff0c;再对得到的XML文本进行解析。首先需要下载一个Apache服务器的安装包&#xff0c;官方下载地址是&#xff1a;http://httpd.apache.org。然后一直点击…

OGR-矢量筛选

OGR-矢量筛选 1.属性筛选 # 根据字段属性进行过滤 ds ogr.Open(os.path.join(data_dir, global)) lyr ds.GetLayer(ne_50m_admin_0_countries) >1 lyr.SetAttributeFilter(continent "Asia") lyr.GetFeatureCount() >2:二次筛选 # You can still get a fe…