详解Spring多数据源如何切换

 更新时间:2024年06月30日 11:21:17   作者:Bug生产猿  
这篇文章主要介绍了spring多数据源的如何切换,由于是spring项目,可以借助 spring 的DataSource 对象去管理,大体思路是创建一个类实现该接口,替换spring原有的DataSource 对象,文中有详细的代码示例供大家参考,需要的朋友可以参考下

由于是spring项目,可以借助 spring 的DataSource 对象去管理,大体思路是创建一个类(比如MyRoutingDataSource)实现该接口,替换spring原有的DataSource 对象,通过MyRoutingDataSource 管理需要spring真实的干活的数据源,这是属于哪种设计模式??

spring jdbc 已经考虑到了,继承spring中 AbstractRoutingDataSource 抽象类实现determineCurrentLookupKey 方法,setTargetDataSources方法用map形式传入所需要切换数据源,是模板方法设计模式??

在Spring框架中实现多数据源配置并切换通常涉及以下步骤:

1.定义数据源

在Spring配置文件中(XML或Java Config)定义多个DataSource bean。

 2.配置JPA或MyBatis

如果你使用JPA,你可能需要为每个数据源配置一个EntityManagerFactoryTransactionManager。如果你使用MyBatis,你可能需要为每个数据源配置一个SqlSessionFactorySqlSessionTemplate

3.使用@Qualifier 或 @Primary

当你有多个相同类型的bean时,你可以使用@Qualifier注解来指定要注入的bean。或者,你可以使用@Primary注解来标记一个数据源作为主要的,以便在不需要明确指定时自动注入。

4.实现数据源路由

数据源路由是实现多数据源切换的关键。你可以通过继承AbstractRoutingDataSource来创建自定义的数据源,该数据源可以根据当前线程或请求上下文中的某个标识符来切换数据源。

5.使用AOP或拦截器设置数据源

在请求处理之前,你可以使用AOP或拦截器来设置当前线程的数据源标识符。这样,当数据访问层(如JPA仓库或MyBatis Mapper)尝试获取数据源时,它将通过你的自定义数据源路由逻辑来获取正确的数据源。

示例代码

自定义数据源路由

public class DynamicDataSource extends AbstractRoutingDataSource {  
  
    @Override  
    protected Object determineCurrentLookupKey() {  
        // 这里可以根据需要返回不同的数据源标识符  
        // 例如,从ThreadLocal中获取当前线程的数据源标识符  
        return DataSourceContextHolder.getCurrentDataSource();  
    }  
}  
  
// 用于保存当前线程的数据源标识符的工具类  
public class DataSourceContextHolder {  
  
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();  
  
    public static void setCurrentDataSource(String dataSource) {  
        contextHolder.set(dataSource);  
    }  
  
    public static String getCurrentDataSource() {  
        return contextHolder.get();  
    }  
  
    public static void clearCurrentDataSource() {  
        contextHolder.remove();  
    }  
}

配置数据源

@Configuration  
public class DataSourceConfig {  
  
    @Bean(name = "primaryDataSource")  
    @ConfigurationProperties(prefix = "spring.datasource.primary")  
    public DataSource primaryDataSource() {  
        // ... 配置并返回DataSource 
        return DataSourceBuilder.create().build(); 
    }  
  
    @Bean(name = "secondaryDataSource")  
    @ConfigurationProperties(prefix = "spring.datasource.secondary")  
    public DataSource secondaryDataSource() {  
        // ... 配置并返回DataSource  
        return DataSourceBuilder.create().build();
    }  
  
    @Bean(name = "dataSource")  
    public DataSource dynamicDataSource() {  
        DynamicDataSource dataSource = new DynamicDataSource();  
        Map<Object, Object> targetDataSources = new HashMap<>();  
        targetDataSources.put("primary", primaryDataSource());  
        targetDataSources.put("secondary", secondaryDataSource());  
        dataSource.setTargetDataSources(targetDataSources);  
        dataSource.setDefaultTargetDataSource(primaryDataSource());  
        return dataSource;  
    }  
  
    // 配置其他必要的组件,如EntityManagerFactory和TransactionManager(如果需要)  
}

使用AOP或拦截器设置数据源

@Aspect  
@Component  
public class DataSourceAspect {  
  
    @Pointcut("@annotation(customDataSource)")  
    public void dataSourcePointcut(CustomDataSource customDataSource) {}  
  
    @Before("dataSourcePointcut(customDataSource)")  
    public void switchDataSource(JoinPoint joinPoint, CustomDataSource customDataSource) {  
        DataSourceContextHolder.setCurrentDataSource(customDataSource.value());  
    }  
  
    @After("@annotation(customDataSource)")  
    public void restoreDataSource(JoinPoint joinPoint, CustomDataSource customDataSource) {  
        DataSourceContextHolder.clearCurrentDataSource();  
    }  
}  
  
// 自定义注解,用于指定数据源  
@Target({ElementType.METHOD, ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
public @interface CustomDataSource {  
  
    String value() default "primary";  
}

现在,你可以在需要指定数据源的方法上使用@CustomDataSource注解来切换数据源。在方法执行之前,AOP切面将设置当前线程的数据源标识符,并在方法执行后清除它。这样,数据访问层就可以通过DynamicDataSource获取正确的数据源了。

到此这篇关于详解Spring多数据源如何切换的文章就介绍到这了,更多相关Spring多数据源切换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java整数(秒数)转换为时分秒格式的示例

    java整数(秒数)转换为时分秒格式的示例

    这篇文章主要介绍了java整数(秒数)转换为时分秒格式的示例,需要的朋友可以参考下
    2014-04-04
  • Java InheritableThreadLocal用法详细介绍

    Java InheritableThreadLocal用法详细介绍

    InheritableThreadLocal继承了ThreadLocal,此类扩展了ThreadLocal以提供从父线程到子线程的值的继承:当创建子线程时,子线程接收父线程具有的所有可继承线程局部变量的初始值。 通常子线程的值与父线程的值是一致的
    2022-09-09
  • Java的Lambda表达式和Stream流的作用以及示例

    Java的Lambda表达式和Stream流的作用以及示例

    这篇文章主要介绍了Java的Lambda表达式和Stream流简单示例,Lambda允许把函数作为一个方法的参数,使用Lambda表达式可以写出更简洁、更灵活的代码,而其作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升,需要的朋友可以参考下
    2023-05-05
  • SpringBoot下使用自定义监听事件的流程分析

    SpringBoot下使用自定义监听事件的流程分析

    事件机制是Spring的一个功能,目前我们使用了SpringBoot框架,所以记录下事件机制在SpringBoot框架下的使用,同时实现异步处理,这篇文章主要介绍了SpringBoot下使用自定义监听事件,需要的朋友可以参考下
    2023-08-08
  • Java jar打包成exe应用程序的详细步骤

    Java jar打包成exe应用程序的详细步骤

    本文主要介绍了Java jar打包成exe应用程序的详细步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • 区分java中String+String和String+char

    区分java中String+String和String+char

    这篇文章主要向大家详细区分了java中String+String和String+char,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • java如何让带T的时间格式化

    java如何让带T的时间格式化

    这篇文章主要介绍了java如何让带T的时间格式化问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Java Process中waitFor()的问题详解

    Java Process中waitFor()的问题详解

    这篇文章主要给大家介绍了关于Java Process中waitFor()问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-12-12
  • springboot yml定义属性,下文中${} 引用说明

    springboot yml定义属性,下文中${} 引用说明

    这篇文章主要介绍了springboot yml定义属性,下文中${} 引用说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • Java实现短信验证码和国际短信群发功能的示例

    Java实现短信验证码和国际短信群发功能的示例

    本篇文章主要介绍了Java实现短信验证码和国际短信群发功能的示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-02-02

最新评论