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

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

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

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

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

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

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

?? 一、基本思路

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

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

1.定義多個(gè)數(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)建動(dò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() 方法返回當(dāng)前應(yīng)該使用的數(shù)據(jù)源標(biāo)識(shí)符。
  • 使用 ThreadLocal 變量存儲(chǔ)每個(gè)線程的數(shù)據(jù)源標(biāo)識(shí)符。

3.注冊動(dòng)態(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è)置默認(rèn)數(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è)置數(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 注解來實(shí)現(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 {
            // 假設(shè)有一個(gè)方法可以根據(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();
    }
}

?? 三、注意事項(xiàng)

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

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

相關(guān)文章

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

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

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

    Mybatis攔截器打印sql問題

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

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

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

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

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

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

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

    Java進(jìn)階之SPI機(jī)制詳解

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

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

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

    SpringBoot通過Nginx代理獲取真實(shí)IP

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

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

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

    Java 8 Lambda 表達(dá)式比較器使用示例代碼

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

最新評(píng)論

大港区| 外汇| 集安市| 金川县| 安国市| 灌云县| 视频| 金平| 筠连县| 县级市| 卢氏县| 沅江市| 余姚市| 中西区| 青铜峡市| 平山县| 礼泉县| 乐昌市| 保康县| 新民市| 临洮县| 鹤峰县| 治县。| 耿马| 疏附县| 宜昌市| 靖安县| 桂林市| 万年县| 公安县| 前郭尔| 枣强县| 开平市| 奇台县| 噶尔县| 东乡族自治县| 长葛市| 石狮市| 宜城市| 鄱阳县| 涿州市|