在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Mybatis 攔截器實現單數據源內多數據庫切換

京東云 ? 來源:京東保險 王奕龍 ? 作者:京東保險 王奕龍 ? 2024-12-12 10:23 ? 次閱讀

作者:京東保險 王奕龍

物流的分揀業務在某些分揀場地只有一個數據源,因為數據量比較大,將所有數據存在一張表內查詢速度慢,也為了做不同設備數據的分庫管理,便在這個數據源內創建了多個不同庫名但表完全相同的數據庫

現在需要上線報表服務來查詢所有數據庫中的數據進行統計,那么現在的問題來了,該如何 滿足在配置一個數據源的情況下來查詢該數據源下不同數據庫的數據 呢,借助搜索引擎查到的分庫實現大多是借助 Sharding-JDBC 框架,配置多個數據源根據分庫算法實現數據源的切換,但是對于只有一個數據源的系統來說,我覺得引入框架再將單個數據源根據不同的庫名配置成多個不同的數據源來實現分庫查詢的邏輯我覺得并不好。

如果我們能在 SQL 執行前將 SQL 中所有的表名前拼接上對應的庫名的話,那么就能夠實現數據源的切換了,下面我們講一下使用 JSqlParser 和 Mybatis攔截器 實現該邏輯,借助 JSqlParser 主要是為了解析SQL,找到其中所有的表名進行拼接,如果大家有更好的實現方式,該組件并不是必須的。

實現邏輯

SqlSource 是讀取 XML 中 SQL 內容并將其發送給數據庫執行的對象,如果我們在執行前能攔截到該對象,并將其中的 SQL 替換掉便達成了我們的目的。 SqlSource 有多種實現,包括常見的DynamicSqlSource。其中包含著必要的執行邏輯,我們需要做的工作便是在這些邏輯執行完之后,對 SQL 進行改造,所以這次實現我們使用了 裝飾器模式,在原來的 SqlSource 上套一層,執行完 SqlSource 本身的方法之后對其進行增強,代碼如下:

public abstract class AbstractDBNameInterceptor {

    /**
     * SqlSource 的裝飾器,作用是增強了 getBoundSql 方法,在基礎上增加了動態分庫的邏輯
     */
    static class SqlSourceDecorator implements SqlSource {

        /**
         * SQL 字段名稱
         */
        private static final String SQL_FIELD_NAME = "sql";

        /**
         * 原本的 sql source
         */
        private final SqlSource sqlSource;

        /**
         * 裝飾器進行封裝
         */
        public SqlSourceDecorator(SqlSource sqlSource) {
            this.sqlSource = sqlSource;
        }

        @Override
        public BoundSql getBoundSql(Object parameterObject) {
            try {
                // 先生成出未修改前的 SQL
                BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
                // 獲取數據庫名
                String dbName = getSpecificDBName(parameterObject);
                // 有效才修改
                if (isValid(dbName)) {
                    // 生成需要修改完庫名的 SQL
                    String targetSQL = getRequiredSqlWithSpecificDBName(boundSql, dbName);
                    // 更新 SQL
                    updateSql(boundSql, targetSQL);
                }

                return boundSql;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * 校驗是否為有效庫名
         */
        private boolean isValid(String dbName) {
            return StringUtils.isNotEmpty(dbName) && !"null".equals(dbName);
        }

        /**
         * 獲取到我們想要的庫名的 SQL
         */
        private String getRequiredSqlWithSpecificDBName(BoundSql boundSql, String dbName) throws JSQLParserException {
            String originSql = boundSql.getSql();
            // 獲取所有的表名
            Set tables = TablesNamesFinder.findTables(originSql);
            for (String table : tables) {
                originSql = originSql.replaceAll(table, dbName + "." + table);
            }
            return originSql;
        }

        /**
         * 修改 SQL
         */
        private void updateSql(BoundSql boundSql, String sql) throws NoSuchFieldException, IllegalAccessException {
            // 通過反射修改sql語句
            Field field = boundSql.getClass().getDeclaredField(SQL_FIELD_NAME);
            field.setAccessible(true);
            field.set(boundSql, sql);
        }
    }
    
    // ... 
}

定義了 AbstractDBNameInterceptor 抽象類是為了實現復用,并將 SqlSourceDecorator 裝飾器定義為靜態內部類,這樣的話,將所有邏輯都封裝在抽象類內部,之后這部分實現好后研發直接實現抽象類的通用方法即可,不必關注它的內部實現。

結合注釋我們解釋一下 SqlSourceDecorator 的邏輯,其中用到了 Java 反射相關的操作。首先通過反射獲取到 SQL,getSpecificDBName 方法是需要自定義實現的,其中 parameterObject 對象是傳到 DAO 層執行查詢時的參數,在我們的業務中是能夠根據其中的設備相關參數拿到對應的所在庫名的,而設備和具體庫名的映射關系需要提前初始化好。在獲取到具體的庫名后執行 getRequiredSqlWithSpecificDBName 方法來將其拼接到表名前,在這里我們使用到了 JSqlParser 的工具類,解析出來所有的表名,執行字符串的替換,最后一步同樣是使用反射操作將該參數值再寫回去,這樣便完成了指定庫名的任務。

接下來我們需要看下抽象攔截器中供攔截器復用的方法,如下:

public abstract class AbstractDBNameInterceptor {

    /**
     * SqlSource 字段名稱
     */
    private static final String SQL_SOURCE_FIELD_NAME = "sqlSource";

    /**
     * 執行修改數據庫名的邏輯
     */
    protected Object updateDBName(Invocation invocation) throws Throwable {
        // 裝飾器裝飾 SqlSource
        decorateSqlSource((MappedStatement) invocation.getArgs()[0]);
        return invocation.proceed();
    }

    /**
     * 裝飾 SqlSource
     */
    private void decorateSqlSource(MappedStatement statement) throws NoSuchFieldException, IllegalAccessException {
        if (!(statement.getSqlSource() instanceof SqlSourceDecorator)) {
            Field sqlSource = statement.getClass().getDeclaredField(SQL_SOURCE_FIELD_NAME);
            sqlSource.setAccessible(true);
            sqlSource.set(statement, new SqlSourceDecorator(statement.getSqlSource()));
        }
    }
}

這個還是比較簡單的,只是借助反射機制做了一層“裝飾”,查詢攔截器實現如下:

@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class SelectDBNameInterceptor extends AbstractDBNameInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        return updateDBName(invocation);
    }
}

將其配置到 Mybatis 攔截器中,便能實現數據庫動態切換了。

審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據庫
    +關注

    關注

    7

    文章

    3876

    瀏覽量

    65451
  • mybatis
    +關注

    關注

    0

    文章

    63

    瀏覽量

    6831
收藏 人收藏

    評論

    相關推薦

    lanbview怎么與數據庫連接?

    擇SQL Server驅動程序,新建一個SQL Server的驅動程序②在“創建SQL Server創建數據源”窗口中輸入“Mydb”作為連接的DSN的名稱,同時根據遠程數據庫服務的配置,在“服務
    發表于 03-22 11:32

    LabView動態創建數據源的方法

    DSN(Data Source Name,數據源名)。LabSQL與數據庫之間的連接就是建立在DSN 基礎之上的。但是這種過于麻煩,在生成操作程序時不便于安裝,于是需要一種可以在LabView中直接創建數據源的方法。通過資料查證
    發表于 09-23 01:53

    LabVIEW連接Access數據庫的問題

    想在LabVIEW中用Access數據庫實現數據操作,但是電腦沒法連上數據源,照著網站上的做法沒有找到數據源,具體情況如圖,最后報錯。
    發表于 11-05 21:45

    QuickBI助你成為分析師——搞定數據源

    分析師”。產品的核心流程如下圖所示,QuickBI實現無縫集成云上數據庫:支持阿里云多種數據源,包括但不限于 MaxCompute、RDS(MySQL、PostgreSQL、SQL Server
    發表于 03-28 12:43

    springboo修改數據源為Druid

    springboo修改數據源Druid整合mybatis 使用Mybatis-Generator插件生成代碼和分頁插件
    發表于 05-05 14:45

    mybatis支持數據庫輕兼容的輕量方案

    一個輕量的方案, 令mybatis支持數據庫輕兼容
    發表于 04-09 17:44

    SpringBoot項目多數據源配置數據庫

    SpringBoot項目多數據源配置
    發表于 06-05 09:51

    數據源配置工具

    odbc_for_access.exe1、可直接配置數據源。2、可直接創建Access數據庫文件。3、為數據庫配置密碼。
    發表于 07-01 16:22 ?4次下載

    springmvc 自定義攔截器實現未登錄用戶的攔截

    springmvc自定義攔截器實現未登錄用戶的攔截
    發表于 11-25 14:44 ?2559次閱讀
    springmvc 自定義<b class='flag-5'>攔截器</b><b class='flag-5'>實現</b>未登錄用戶的<b class='flag-5'>攔截</b>

    數據倉庫入門之創建數據源

    首先需要創建一個數據源,SSAS(分析服務)將利用數據源來連接數據庫。一、準備環境二、啟動SSDT,新建項目三、創建數據源
    發表于 02-24 14:48 ?2623次閱讀
    <b class='flag-5'>數據</b>倉庫入門之創建<b class='flag-5'>數據源</b>

    基于Mybatis攔截器實現數據范圍權限

    前端的菜單和按鈕權限都可以通過配置來實現,但很多時候,后臺查詢數據庫數據的權限需要通過手動添加SQL來實現
    的頭像 發表于 06-20 09:57 ?1574次閱讀
    基于<b class='flag-5'>Mybatis</b><b class='flag-5'>攔截器</b><b class='flag-5'>實現</b><b class='flag-5'>數據</b>范圍權限

    如何實現基于Mybatis攔截器實現數據范圍權限呢?

    前端的菜單和按鈕權限都可以通過配置來實現,但很多時候,后臺查詢數據庫數據的權限需要通過手動添加SQL來實現
    的頭像 發表于 06-20 09:59 ?1417次閱讀
    如何<b class='flag-5'>實現</b>基于<b class='flag-5'>Mybatis</b><b class='flag-5'>攔截器</b><b class='flag-5'>實現</b><b class='flag-5'>數據</b>范圍權限呢?

    多數據源數據轉換和同步的ETL工具推薦

    多種數據源的連接,包括文件系統、數據庫、消息隊列、網絡接口等。它提供了可視化的界面和強大的數據處理功能,可以輕松地創建數據流,進行數據轉換和
    的頭像 發表于 07-28 16:32 ?1302次閱讀

    SpringBoot實現動態切換數據源

    最近在做業務需求時,需要從不同的數據庫中獲取數據然后寫入到當前數據庫中,因此涉及到切換數據源問題。本來想著使用
    的頭像 發表于 12-08 10:53 ?1168次閱讀
    SpringBoot<b class='flag-5'>實現</b>動態<b class='flag-5'>切換</b><b class='flag-5'>數據源</b>

    一種輕量分表方案-MyBatis攔截器分表實踐

    文章,將分享如何使用MyBatis攔截器低成本的提升數據庫穩定性。 業界常見方案 針對冷數據多的大表,常用的策略有以2種: 刪除/歸檔舊數據
    的頭像 發表于 01-23 17:38 ?297次閱讀
    主站蜘蛛池模板: 亚洲一级毛片免费看 | 乡村乱人伦短小说 | 国产小片 | 久久综合色综合 | www.a级片| 69xxxx日本| 人人做人人澡人人人爽 | 成年片色大黄全免费网址 | 日本一区二区三区在线观看视频 | www.四虎影院.con | 手机看片日韩永久福利盒子 | 免费一区二区视频 | 久久免费看 | 一级片在线观看视频 | 热门国产xvideos中文 | 一级特黄a免费大片 | 亚洲一区二区三区四区在线观看 | 久久这里只有精品1 | 视频在线观看免费播放www | 国产综合在线播放 | 天天狠天天干 | 前后灌满白浆护士 | 人人射人人爽 | 色香视频在线 | 亚洲精品亚洲人成毛片不卡 | 黄色免费在线网站 | 高清在线免费观看 | 新版天堂资源在线官网8 | 亚洲天堂视频在线播放 | 性欧美www | 国产h视频在线观看 | 色聚网久久综合 | 日本边添边爱边摸边做边爱 | 日本一卡精品视频免费 | 福利色播| 亚洲综合精品一区二区三区中文 | 久久综合久久久 | 亚洲精品成人网 | 色吊丝中文字幕 | 色婷婷六月丁香在线观看 | 亚洲综合一二三区 |