最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

?? 一句話總結(jié):

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

?? 一、基本思路

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

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

1.定義多個數(shù)據(jù)源

@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)數(shù)據(jù)源路由

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() 方法返回當前應該使用的數(shù)據(jù)源標識符。
  • 使用 ThreadLocal 變量存儲每個線程的數(shù)據(jù)源標識符。

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

@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); // 設置默認數(shù)據(jù)源
        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 {
        // 根據(jù)請求路徑或其他條件設置數(shù)據(jù)源
        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 {
            // 假設有一個方法可以根據(jù)某些條件確定要使用的數(shù)據(jù)源
            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 來存儲數(shù)據(jù)源標識符,因此在每次請求結(jié)束時都必須清理該變量,以防止內(nèi)存泄漏或跨請求污染。
  • 事務管理:如果涉及到事務,需確保事務與數(shù)據(jù)源綁定正確。通常情況下,Spring 的事務管理器會自動處理這個問題,但如果你手動管理事務,可能需要額外注意。
  • 性能考慮:頻繁地切換數(shù)據(jù)源可能會帶來一定的性能開銷,尤其是在高并發(fā)場景下。因此,應盡量減少不必要的切換頻率。
  • 異常處理:確保在發(fā)生異常時也能正確地清理上下文,避免潛在的問題。

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

相關文章

  • SpringBoot整合MongoDB實現(xiàn)文件上傳下載刪除

    SpringBoot整合MongoDB實現(xiàn)文件上傳下載刪除

    這篇文章主要介紹了SpringBoot整合MongoDB實現(xiàn)文件上傳下載刪除的方法,幫助大家更好的理解和學習使用SpringBoot框架,感興趣的朋友可以了解下
    2021-05-05
  • Mybatis攔截器打印sql問題

    Mybatis攔截器打印sql問題

    這篇文章主要介紹了Mybatis攔截器打印sql問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java讀取properties文件之中文亂碼問題及解決

    Java讀取properties文件之中文亂碼問題及解決

    這篇文章主要介紹了Java讀取properties文件之中文亂碼問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 解決IDEA插件市場Plugins無法加載的問題

    解決IDEA插件市場Plugins無法加載的問題

    這篇文章主要介紹了解決IDEA插件市場Plugins無法加載的問題,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • 集群環(huán)境中使用ehcache_動力節(jié)點Java學院整理

    集群環(huán)境中使用ehcache_動力節(jié)點Java學院整理

    這篇文章主要為大家詳細介紹了集群環(huán)境中使用ehcache的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Java進階之SPI機制詳解

    Java進階之SPI機制詳解

    Java SPI機制在很多大型中間建碼,例如Dubbo中均有采用,屬于高級Java開發(fā)的進階必備知識點,務必要求掌握.文中有非常詳細的代碼示例及解釋,需要的朋友可以參考下
    2021-05-05
  • Java內(nèi)存泄漏問題處理方法經(jīng)驗總結(jié)

    Java內(nèi)存泄漏問題處理方法經(jīng)驗總結(jié)

    今天小編就為大家分享一篇關于Java內(nèi)存泄漏問題處理方法經(jīng)驗總結(jié),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • SpringBoot通過Nginx代理獲取真實IP

    SpringBoot通過Nginx代理獲取真實IP

    springboot作為后臺代碼,獲取到的登錄IP是前臺的代理服務器地址,并不是用戶的真實IP地址,本文主要介紹了SpringBoot通過Nginx代理獲取真實IP,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • YGC前后新生代是否變大分析詳解

    YGC前后新生代是否變大分析詳解

    要解釋這個問題,我們先要弄清楚YGC的過程,parNew是新生代的gc算法,簡單來說從gc roots開始掃描對象,當掃到一個只要是屬于新生代的對象就將其挪到to space,但是老的對象還不會做釋放,直到gc完成之后再看是否釋放老的對象
    2022-01-01
  • Java 8 Lambda 表達式比較器使用示例代碼

    Java 8 Lambda 表達式比較器使用示例代碼

    這篇文章主要介紹了Java 8 Lambda 表達式比較器使用示例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08

最新評論

绥棱县| 望奎县| 高碑店市| 建阳市| 资溪县| 辽源市| 拉萨市| 博客| 隆林| 茶陵县| 革吉县| 岳普湖县| 万源市| 剑河县| 桐梓县| 叙永县| 灌南县| 楚雄市| 大安市| 鄂尔多斯市| 巴彦淖尔市| 金乡县| 凤台县| 交口县| 甘孜县| 阜宁县| 甘洛县| 吉隆县| 沛县| 长岛县| 韩城市| 汶上县| 湘阴县| 高州市| 报价| 淮滨县| 大新县| 肥西县| 栾川县| 四川省| 新邵县|