qidao123.com技术社区-IT企服评测·应用市场

标题: Spring框架中数据库动态切换实战详解 [打印本页]

作者: 莫张周刘王    时间: 3 天前
标题: Spring框架中数据库动态切换实战详解
本文还有配套的佳构资源,点击获取  

  简介:在Spring框架中,数据库动态切换是一个关键特性,它使得应用程序能够根据特定条件在多个数据库之间机动切换。本文深入探究如何配置和实现这一功能,包括设置多个数据源、利用  AbstractRoutingDataSource  进行动态选择,以及界说和注册自界说的路由数据源。此外,提供了相应的测试用例来验证切换逻辑的正确性。本文还大概包罗示例代码、配置文件和引导文档,以帮助理解并实践这一高级特性。

1. Spring多数据库毗连受理

  在今世的IT架构中,尤其是在构建大型的企业级应用时,常常会遇到必要毗连多个数据库的场景。例如,在一个电子商务平台中,大概必要一个数据库来处理商品信息,另一个数据库处理用户订单信息,第三个数据库处理物流信息等等。这就要求我们的应用能够机动地管理多个数据库毗连,并在必要的时间进行切换。
  在Spring框架中,提供了对多数据源毗连受理的优秀支持,这可以通过配置多个  DataSource  实例来实现。我们将首先了解如何配置多个  DataSource  实例,并掌握其属性设置的关键点,这将为我们后续章节中详细介绍如何动态选择和切换数据源打下坚固的基础。下面,我们将具体探究如何配置这些数据源,并理解它们如安在应用程序中被利用。
2. 配置多个DataSource实例

  在今世企业级应用中,单一数据源配置往往无法满意复杂业务场景的需求。特殊是对于微服务架构,每个服务大概必要毗连到差异的数据库以支持业务隔离和数据同等性。Spring框架提供了强盛的支持,可以帮助开发者配置和管理多个数据源实例。本章节将详细介绍如何通过XML配置文件和Spring Boot配置类来实现多个DataSource实例的配置。
2.1 DataSource的配置方法

2.1.1 利用XML配置文件进行DataSource配置

  在传统Spring应用中,XML配置文件是配置数据源的告急方式。通过界说bean和属性,开发者可以详细配置每个数据源的毗连信息。以下是一个基于XML配置的示例:
  1. <!-- 配置第一个数据源 -->
  2. <bean id="dataSourceMaster" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  3.     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  4.     <property name="url" value="jdbc:mysql://localhost:3306/master_db"/>
  5.     <property name="username" value="root"/>
  6.     <property name="password" value="password"/>
  7.     <!-- 其他连接池相关配置 -->
  8. </bean>
  9. <!-- 配置第二个数据源 -->
  10. <bean id="dataSourceSlave" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  11.     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  12.     <property name="url" value="jdbc:mysql://localhost:3306/slave_db"/>
  13.     <property name="username" value="root"/>
  14.     <property name="password" value="password"/>
  15.     <!-- 其他连接池相关配置 -->
  16. </bean>
复制代码
在上述XML配置中,我们界说了两个数据源实例  dataSourceMaster  和  dataSourceSlave  ,并分别设置了对应的驱动类名、数据库URL、用户名和暗码。值得留意的是,这里利用了  org.apache.commons.dbcp.BasicDataSource  作为数据源实现,它允许我们设置毗连池相关属性,如最大毗连数、最大等待时间等。
2.1.2 利用Spring Boot配置类进行配置

  随着Spring Boot的盛行,越来越多的开发者倾向于通过Java配置类来替代XML配置文件。Spring Boot提供了  @Configuration  注解来界说配置类,并利用  @Bean  注解来注册数据源实例。
  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import com.zaxxer.hikari.HikariDataSource;
  4. import javax.sql.DataSource;
  5. @Configuration
  6. public class DataSourceConfig {
  7.     @Bean(name = "dataSourceMaster")
  8.     public DataSource dataSourceMaster() {
  9.         HikariDataSource dataSource = new HikariDataSource();
  10.         dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/master_db");
  11.         dataSource.setUsername("root");
  12.         dataSource.setPassword("password");
  13.         dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  14.         // 其他连接池相关配置
  15.         return dataSource;
  16.     }
  17.     @Bean(name = "dataSourceSlave")
  18.     public DataSource dataSourceSlave() {
  19.         HikariDataSource dataSource = new HikariDataSource();
  20.         dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/slave_db");
  21.         dataSource.setUsername("root");
  22.         dataSource.setPassword("password");
  23.         dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  24.         // 其他连接池相关配置
  25.         return dataSource;
  26.     }
  27. }
复制代码
在这个配置类中,我们利用了  HikariDataSource  作为数据源实现,并利用  @Bean  注解分别界说了  dataSourceMaster  和  dataSourceSlave  两个数据源实例。这种方式使得配置更加简洁和范例安全。
2.2 DataSource的属性设置

2.2.1 数据库毗连池相关属性配置

  无论是利用XML配置文件照旧Java配置类,对数据源毗连池的配置都是至关告急的。毗连池可以明显进步数据库操作的性能和稳定性。以下是一些常见的数据库毗连池属性配置项:
  | 属性名 | 说明 | 默认值 | | --- | --- | --- | | maximumPoolSize | 毗连池中最大毗连数 | 10 | | minimumIdle | 毗连池维护的最小空闲毗连数 | 0 | | maxLifetime | 毗连最大生命周期(毫秒) | 1800000 | | connectionTimeout | 毗连获取超时时间(毫秒) | 30000 | | idleTimeout | 毗连空闲超时时间(毫秒) | 600000 |
  正确配置这些属性可以帮助开发者更有用地管理数据库毗连,而且制止因资源耗尽导致的标题。
2.2.2 驱动和毗连字符串的配置

  除了毗连池属性外,驱动(Driver)和毗连字符串(Connection String)是配置数据源的两个告急部分。毗连字符串界说了如何访问数据库,而驱动则是确保数据库毗连得以建立的关键组件。
  毗连字符串通常遵循特定的格式,以MySQL为例,其格式如下:
  1. jdbc:mysql://<host>:<port>/<database>
复制代码
其中,  <host>  是数据库服务器地址,  <port>  是数据库服务器端口(MySQL默认端口是3306),而  <database>  则是要毗连的数据库名。在实际配置中,这些信息必要根据实际情况进行替换。
  驱动的配置则涉及到选择合适的数据库驱动类,例如,对于MySQL,驱动类名为  com.mysql.jdbc.Driver  ,而针对MariaDB,则大概是  org.mariadb.jdbc.Driver  。正确配置驱动可以确保应用能够正确地与数据库进行交互。
  通过本章节的介绍,我们可以了解到Spring中配置多个DataSource实例的基本方法,以及如何设置毗连池属性和驱动。这些内容是构建支持多个数据源Spring应用的基础,为后续章节中动态数据源的实现和业务逻辑的机动操作奠基了基础。在下一章中,我们将深入探究利用  AbstractRoutingDataSource  实现动态数据源选择的原理和实践步骤。
3. 利用AbstractRoutingDataSource实现动态选择

3.1 AbstractRoutingDataSource的原理

3.1.1 动态数据源的核心头脑

  在多数据源场景中,核心标题是如何根据实际必要,动态地切换到对应的DataSource实例。AbstractRoutingDataSource是Spring提供的一个抽象类,可以用来实现动态数据源的选择逻辑。它的核心头脑是通过一个线程安全的方式来存储当前的DataSource上下文,根据上下文的值来决定利用哪个DataSource。
  AbstractRoutingDataSource实现了DataSource接口,这意味着它可以直接被Spring管理,并可以注入到DAO层中。当DAO层调用Connection的时间,实际上是通过当前的DataSource上下文来获取相应的Connection。当必要切换数据源时,只必要修改存储在ThreadLocal中的上下文值即可。
3.1.2 AbstractRoutingDataSource的类布局分析

  AbstractRoutingDataSource继承了抽象类AbstractDataSource,并重写了determineTargetDataSource方法。此方法会根据当前上下文中的信息返回一个具体的数据源实例。具体的实现通常是通过一个Map来映射差异的数据源键值对,并根据当前的键值来找到对应的DataSource。
  1. public abstract class AbstractRoutingDataSource extends AbstractDataSource {
  2.     protected Map<Object, Object> targetDataSources;
  3.     private Object defaultTargetDataSource;
  4.     private boolean lenientFallback = true;
  5.     @Override
  6.     protected Object determineTargetDataSource() {
  7.         Assert.notNull(this.targetDataSources, "Property 'targetDataSources' is required");
  8.         Object lookupKey = determineCurrentLookupKey();
  9.         Object targetDataSource = this.targetDataSources.get(lookupKey);
  10.         if (targetDataSource == null && this.lenientFallback) {
  11.             targetDataSource = this.defaultTargetDataSource;
  12.         }
  13.         if (targetDataSource == null) {
  14.             throw new DataSourceLookupFailureException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
  15.         }
  16.         return targetDataSource;
  17.     }
  18.     // ...
  19. }
复制代码
3.2 动态数据源的实现步骤

3.2.1 界说动态数据源类继承AbstractRoutingDataSource

  创建一个新的类继承自AbstractRoutingDataSource,实现determineCurrentLookupKey方法,该方法返回当前线程利用的数据源的键值。键值通常是一个String大概是一个自界说的枚举范例。
  1. public class DynamicDataSource extends AbstractRoutingDataSource {
  2.     @Override
  3.     protected Object determineCurrentLookupKey() {
  4.         // 获取当前线程的数据源上下文值
  5.         return DataSourceContextHolder.getDataSourceType();
  6.     }
  7. }
复制代码
3.2.2 实现数据源的切换逻辑

  通过自界说的线程存储(如DataSourceContextHolder),我们可以设置当前线程利用的数据源键值。这个存储必要是线程安全的,例如利用ThreadLocal。每次必要切换数据源时,调用设置方法来更新存储的键值。
  1. public class DataSourceContextHolder {
  2.     private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
  3.     public static void setDataSourceType(String dataSourceType) {
  4.         contextHolder.set(dataSourceType);
  5.     }
  6.     public static String getDataSourceType() {
  7.         return contextHolder.get();
  8.     }
  9.     public static void clearDataSourceType() {
  10.         contextHolder.remove();
  11.     }
  12. }
复制代码
实现切换逻辑通常是在差异的业务处理方法前设置好数据源键值,在方法结束后扫除键值,包管数据源上下文的正确隔离。
  在实际利用中,我们往往会在拦截器、过滤器大概切面中根据实际情况(如用户身份、业务逻辑)来设置键值,这样可以减少在业务代码中直接处理数据源切换的复杂性。
  以上就是AbstractRoutingDataSource的基本原理和实现步骤。通过这种方式,我们可以机动地在应用程序中管理多个数据源,实现数据源的动态选择。
4. 自界说RoutingDataSource的界说和注册

4.1 自界说RoutingDataSource的界说

4.1.1 创建自界说RoutingDataSource类

  在Spring框架中实现数据库动态切换的一个关键步骤是创建一个自界说的  RoutingDataSource  类,它继承自  AbstractRoutingDataSource  。  AbstractRoutingDataSource  是Spring提供的一个抽象类,它允许我们实现自己的数据源路由逻辑。
  以下是自界说  RoutingDataSource  类的一个简单实现示例:
  1. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  2. public class CustomRoutingDataSource extends AbstractRoutingDataSource {
  3.     @Override
  4.     protected Object determineCurrentLookupKey() {
  5.         // 返回当前线程的上下文中存储的数据源标识符
  6.         return DataSourceContextHolder.getDataSourceType();
  7.     }
  8. }
复制代码
在这个类中,  determineCurrentLookupKey  方法是关键,它根据当前线程的上下文返回一个代表数据源的键。实际的数据源切换逻辑是在  DataSourceContextHolder  中实现的,这是一个存储当前线程所利用的数据源标识符的工具类。
4.1.2 实现数据源键的获取和存储机制

  在  AbstractRoutingDataSource  的子类中,我们必要提供一种机制来获取当前线程的数据源标识符,并将其存储起来供  determineCurrentLookupKey  方法利用。这通常是通过一个线程局部变量来实现的,下面是一个简单的  DataSourceContextHolder  类的实现:
  1. import org.springframework.stereotype.Component;
  2. import java.util.concurrent.ConcurrentHashMap;
  3. import java.util.concurrent.atomic.AtomicInteger;
  4. @Component
  5. public class DataSourceContextHolder {
  6.     private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
  7.     private static final ConcurrentHashMap<String, AtomicInteger> dataSourceUsageCount = new ConcurrentHashMap<>();
  8.     public static void setDataSourceType(String dataSourceType) {
  9.         contextHolder.set(dataSourceType);
  10.     }
  11.     public static String getDataSourceType() {
  12.         return contextHolder.get();
  13.     }
  14.     public static void clearDataSourceType() {
  15.         contextHolder.remove();
  16.     }
  17.     public static void incrementUsageCount(String dataSourceType) {
  18.         dataSourceUsageCount.computeIfAbsent(dataSourceType, k -> new AtomicInteger(0)).incrementAndGet();
  19.     }
  20.     public static void decrementUsageCount(String dataSourceType) {
  21.         if (dataSourceUsageCount.containsKey(dataSourceType)) {
  22.             dataSourceUsageCount.get(dataSourceType).decrementAndGet();
  23.         }
  24.     }
  25.     public static int getUsageCount(String dataSourceType) {
  26.         return dataSourceUsageCount.getOrDefault(dataSourceType, new AtomicInteger(0)).get();
  27.     }
  28. }
复制代码
这个类利用了  ThreadLocal  来存储每个线程的数据源标识符,并提供了几个辅助方法来进行操作。  incrementUsageCount  和  decrementUsageCount  方法用于记录数据源的利用次数,这对于监控和平衡多数据源的负载非常有用。
4.2 自界说RoutingDataSource的注册与利用

4.2.1 将自界说RoutingDataSource注册到Spring容器

  一旦我们创建了自界说的  RoutingDataSource  类,下一步就是将其注册到Spring容器中,以确保Spring能够管理它。通常,这涉及到在Spring配置类中创建一个Bean,如下所示:
  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. @Configuration
  4. public class DataSourceConfig {
  5.     @Bean
  6.     public CustomRoutingDataSource customRoutingDataSource() {
  7.         CustomRoutingDataSource customRoutingDataSource = new CustomRoutingDataSource();
  8.         // 配置具体的DataSource实现,比如HikariDataSource, DBCPDataSource等
  9.         // 设置targetDataSources,这里需要根据实际情况配置
  10.         // 设置defaultTargetDataSource,如果未匹配到key,则使用默认数据源
  11.         return customRoutingDataSource;
  12.     }
  13. }
复制代码
在这个配置类中,我们创建了  CustomRoutingDataSource  的Bean,而且可以配置目标数据源和其他相关属性。这使得Spring能够主动管理数据源切换的生命周期。
4.2.2 在业务逻辑中利用自界说RoutingDataSource

  在业务逻辑中利用自界说  RoutingDataSource  通常涉及在特定方法或服务中设置数据源上下文,之后执行的数据库操作将基于该上下文选择正确的数据源。这个过程可以利用  @Transactional  注解来管理事件,确保数据的同等性。
  1. @Service
  2. public class SomeService {
  3.     @Transactional
  4.     public void usePrimaryDataSource() {
  5.         // 操作主数据源
  6.         DataSourceContextHolder.setDataSourceType("primary");
  7.         // 这里的数据库操作将会使用主数据源
  8.     }
  9.     @Transactional
  10.     public void useSecondaryDataSource() {
  11.         // 操作次级数据源
  12.         DataSourceContextHolder.setDataSourceType("secondary");
  13.         // 这里的数据库操作将会使用次级数据源
  14.     }
  15. }
复制代码
在这个服务类中,我们通过设置  DataSourceContextHolder  中的数据源标识符来改变当前线程的上下文。当  @Transactional  注解的方法执行时,Spring会根据当前线程的数据源上下文来选择正确的数据源进行数据库操作。
  通过上述章节内容,我们可以看到,自界说  RoutingDataSource  的界说和注册是一个必要细致考量的过程,确保它能够正确地集成到Spring应用中,而且在业务逻辑中机动利用,从而实现对多数据源情况的精确控制。
5. 数据库动态切换的业务逻辑实现

  在构建复杂的业务系统时,常常会遇到必要根据差异的业务场景大概用户范例毗连差异数据库的场景。动态数据源切换能够在运行时根据特定的规则选择合适的数据库毗连,从而加强系统的机动性和可维护性。本章节将深入探究如安在业务逻辑中实现数据源的动态切换。
5.1 业务逻辑中数据源切换的场景分析

  在多数据库系统中,数据源切换的场景大概涉及但不限于以下几点:
5.1.1 根据用户范例切换数据源

  在多租户系统中,差异租户大概拥有自己的数据库,因此必要根据用户登录信息来选择相应的数据源。例如,一个教诲系统大概包罗门生、教师和管理员三种用户范例,每种范例的用户大概对应差异的数据源。
5.1.2 根据业务需求切换数据源

  在某些业务逻辑中,大概必要根据业务需求访问差异的数据库。例如,在一个电商系统中,处理订单的业务逻辑必要访问订单数据库,而产物查询则大概访问产物数据库。
5.2 实现数据源切换的代码示例

  要实现数据源的动态切换,可以利用  ThreadLocal  作为数据源切换的桥梁,大概通过 Spring 的  @Transactional  注解进行事件管理来实现。
5.2.1 利用ThreadLocal进行数据源选择

  1. public class DataSourceContextHolder {
  2.     private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
  3.     public static void setDataSourceType(String dataSourceType) {
  4.         contextHolder.set(dataSourceType);
  5.     }
  6.     public static String getDataSourceType() {
  7.         return contextHolder.get();
  8.     }
  9.     public static void clearDataSourceType() {
  10.         contextHolder.remove();
  11.     }
  12. }
复制代码
在上述代码中,  DataSourceContextHolder  类利用  ThreadLocal  来生存线程级别的数据源范例。在业务逻辑开始前,根据业务必要设置数据源范例,并在业务逻辑结束时扫除。
5.2.2 实现多数据源情况下的事件管理

  为了在多数据源情况中进行有用的事件管理,必要配置  PlatformTransactionManager  来指定事件应该利用哪个数据源。以下是如何配置事件管理器的示例代码:
  1. @Configuration
  2. public class TransactionConfig {
  3.     @Bean(name = "transactionManager1")
  4.     @Primary
  5.     @DependsOn("dataSource1")
  6.     public PlatformTransactionManager transactionManager1(@Qualifier("dataSource1") DataSource dataSource) {
  7.         return new DataSourceTransactionManager(dataSource);
  8.     }
  9.     @Bean(name = "transactionManager2")
  10.     @DependsOn("dataSource2")
  11.     public PlatformTransactionManager transactionManager2(@Qualifier("dataSource2") DataSource dataSource) {
  12.         return new DataSourceTransactionManager(dataSource);
  13.     }
  14. }
复制代码
通过界说多个事件管理器  transactionManager1  ,  transactionManager2  等,并将它们绑定到各自的  DataSource  ,可以在差异的数据源上进行事件操作。
  以上就是实现数据库动态切换的业务逻辑方法,通过机动地利用  ThreadLocal  和  PlatformTransactionManager  可以有用地在多数据源情况中切换和管理事件。通过这种机制,开发者可以构建更加复杂和功能丰富的应用程序。
  在实现数据源切换的过程中,确保每个数据源都被正确管理和配置黑白常告急的。每个数据源的配置和管理都是独立的,而Spring框架提供了丰富的工具和API来支持这些操作。接下来的章节,将介绍如何测试和验证数据库切换功能。
   本文还有配套的佳构资源,点击获取  

  简介:在Spring框架中,数据库动态切换是一个关键特性,它使得应用程序能够根据特定条件在多个数据库之间机动切换。本文深入探究如何配置和实现这一功能,包括设置多个数据源、利用  AbstractRoutingDataSource  进行动态选择,以及界说和注册自界说的路由数据源。此外,提供了相应的测试用例来验证切换逻辑的正确性。本文还大概包罗示例代码、配置文件和引导文档,以帮助理解并实践这一高级特性。
   本文还有配套的佳构资源,点击获取  



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4