欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring通過攔截器實現(xiàn)多數據源切換的示例代碼

 更新時間:2025年08月20日 10:02:16   作者:南姜先生  
本文主要介紹了Spring攔截器實現(xiàn)多數據源動態(tài)切換,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

在 Spring 應用中,特別是使用了多數據源的場景下,可以通過**攔截器(Interceptor)**機制來實現(xiàn)動態(tài)數據源切換。Spring 提供了多種方式來管理多個數據源,并允許開發(fā)者根據業(yè)務邏輯的需求靈活地選擇不同的數據源進行數據庫操作。

下面介紹如何通過攔截器實現(xiàn)多數據源切換的基本思路和具體步驟。

?? 一句話總結:

? 通過自定義 HandlerInterceptor 或 MyBatis 的 Interceptor 攔截請求或 SQL 執(zhí)行過程,在合適的時機動態(tài)設置當前線程的數據源,從而實現(xiàn)基于請求或方法級別的多數據源切換。

?? 一、基本思路

  1. 配置多個數據源:首先需要在 Spring 配置類中定義多個 DataSource Bean。
  2. 動態(tài)數據源路由:創(chuàng)建一個代理數據源,它能夠根據某些條件(如當前線程中的某個標識符)選擇實際使用的數據源。
  3. 攔截請求或方法調用:使用 Spring MVC 的 HandlerInterceptor 或 MyBatis 的 Interceptor 來攔截請求或方法調用,在執(zhí)行之前設置當前線程的數據源標識符。
  4. 清除上下文:確保在請求結束后清理線程局部變量,避免影響后續(xù)請求。

??? 二、具體實現(xiàn)步驟

1.定義多個數據源

@Configuration
public class DataSourceConfig {

    @Bean(name = "primaryDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}

2.創(chuàng)建動態(tài)數據源路由

public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    @Override
    protected Object determineCurrentLookupKey() {
        return contextHolder.get();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }
}
  • determineCurrentLookupKey() 方法返回當前應該使用的數據源標識符。
  • 使用 ThreadLocal 變量存儲每個線程的數據源標識符。

3.注冊動態(tài)數據源

@Configuration
public class DynamicDataSourceConfig {

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("primary", primaryDataSource);
        targetDataSources.put("secondary", secondaryDataSource);

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(primaryDataSource); // 設置默認數據源
        return dynamicDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }
}

4.編寫攔截器

a.Spring MVC 攔截器

@Component
public class DataSourceInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 根據請求路徑或其他條件設置數據源
        if (request.getRequestURI().startsWith("/api/secondary")) {
            DynamicDataSource.setDataSource("secondary");
        } else {
            DynamicDataSource.setDataSource("primary");
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        DynamicDataSource.clearDataSource(); // 清理線程局部變量
    }
}

b.MyBatis 攔截器

如果你想要基于 MyBatis 的 @Intercepts 注解來實現(xiàn),則可以這樣做:

@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
             @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class DataSourceInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        try {
            // 假設有一個方法可以根據某些條件確定要使用的數據源
            String dataSourceKey = determineDataSourceKey(invocation.getMethod().getName());
            DynamicDataSource.setDataSource(dataSourceKey);

            return invocation.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

5.注冊攔截器

a.Spring MVC 攔截器注冊

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private DataSourceInterceptor dataSourceInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(dataSourceInterceptor).addPathPatterns("/**");
    }
}

b.MyBatis 攔截器注冊

如果你使用的是 MyBatis 攔截器,可以在配置類中添加如下代碼:

@Configuration
public class MyBatisConfig {

    @Autowired
    private DataSourceInterceptor myBatisDataSourceInterceptor;

    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setPlugins(new Interceptor[]{myBatisDataSourceInterceptor});
        return sessionFactory.getObject();
    }
}

?? 三、注意事項

  • 線程安全:由于我們使用了 ThreadLocal 來存儲數據源標識符,因此在每次請求結束時都必須清理該變量,以防止內存泄漏或跨請求污染。
  • 事務管理:如果涉及到事務,需確保事務與數據源綁定正確。通常情況下,Spring 的事務管理器會自動處理這個問題,但如果你手動管理事務,可能需要額外注意。
  • 性能考慮:頻繁地切換數據源可能會帶來一定的性能開銷,尤其是在高并發(fā)場景下。因此,應盡量減少不必要的切換頻率。
  • 異常處理:確保在發(fā)生異常時也能正確地清理上下文,避免潛在的問題。

到此這篇關于Spring通過攔截器實現(xiàn)多數據源切換的示例代碼的文章就介紹到這了,更多相關Spring 攔截器多數據源切換內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java并發(fā)高的情況下用ThreadLocalRandom來生成隨機數

    java并發(fā)高的情況下用ThreadLocalRandom來生成隨機數

    如果我們想要生成一個隨機數,通常會使用Random類。但是在并發(fā)情況下Random生成隨機數的性能并不是很理想,本文主要介紹了java并發(fā)高的情況下用ThreadLocalRandom來生成隨機數,感興趣的可以了解一下
    2022-05-05
  • 基于springboot攔截器HandlerInterceptor的注入問題

    基于springboot攔截器HandlerInterceptor的注入問題

    這篇文章主要介紹了springboot攔截器HandlerInterceptor的注入問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java中線程休眠編程實例

    Java中線程休眠編程實例

    這篇文章主要介紹了Java中線程休眠編程實例,本文直接給出代碼實例,并對休眠方法做了一番講解,需要的朋友可以參考下
    2015-06-06
  • SpringCloud Alibaba Seata (收藏版)

    SpringCloud Alibaba Seata (收藏版)

    Seata是一款開源的分布式事務解決方案,致力于在微服務架構在提供高性能和簡單一樣的分布式事務服務。這篇文章主要介紹了SpringCloud Alibaba Seata 的相關知識,需要的朋友可以參考下
    2020-10-10
  • eclipse導入工程報錯問題項目或者文件有紅叉的解決方案

    eclipse導入工程報錯問題項目或者文件有紅叉的解決方案

    這篇文章主要介紹了eclipse導入工程報錯問題項目或者文件有紅叉的解決方案,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • 在Spring Data JPA中引入Querydsl的實現(xiàn)方式

    在Spring Data JPA中引入Querydsl的實現(xiàn)方式

    這篇文章主要介紹了在Spring Data JPA中引入Querydsl的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • Spring?Boot中JSON數值溢出問題從報錯到優(yōu)雅解決辦法

    Spring?Boot中JSON數值溢出問題從報錯到優(yōu)雅解決辦法

    這篇文章主要介紹了Spring?Boot中JSON數值溢出問題從報錯到優(yōu)雅的解決辦法,通過修改字段類型為Long、添加全局異常處理和數據校驗,解決了該問題,文章還提供了類型范圍推薦場景和常見問題解答,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-04-04
  • spring boot 測試單元修改數據庫不成功的解決

    spring boot 測試單元修改數據庫不成功的解決

    這篇文章主要介紹了spring boot 測試單元修改數據庫不成功的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 深入解析Java中的Classloader的運行機制

    深入解析Java中的Classloader的運行機制

    這篇文章主要介紹了Java中的Classloader的運行機制,包括從JVM方面講解類加載器的委托機制等,需要的朋友可以參考下
    2015-11-11
  • Springboot如何根據docx填充生成word文件并導出pdf

    Springboot如何根據docx填充生成word文件并導出pdf

    這篇文章主要介紹了Springboot如何根據docx填充生成word文件并導出pdf問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08

最新評論