色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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

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

3天內不再提示

Mybatis 攔截器實現(xiàn)單數(shù)據(jù)源內多數(shù)據(jù)庫切換

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

作者:京東保險 王奕龍

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

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

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

實現(xiàn)邏輯

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

public abstract class AbstractDBNameInterceptor {

    /**
     * SqlSource 的裝飾器,作用是增強了 getBoundSql 方法,在基礎上增加了動態(tài)分庫的邏輯
     */
    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);
                // 獲取數(shù)據(jù)庫名
                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 抽象類是為了實現(xiàn)復用,并將 SqlSourceDecorator 裝飾器定義為靜態(tài)內部類,這樣的話,將所有邏輯都封裝在抽象類內部,之后這部分實現(xiàn)好后研發(fā)直接實現(xiàn)抽象類的通用方法即可,不必關注它的內部實現(xiàn)。

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

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

public abstract class AbstractDBNameInterceptor {

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

    /**
     * 執(zhí)行修改數(shù)據(jù)庫名的邏輯
     */
    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()));
        }
    }
}

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

@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 攔截器中,便能實現(xiàn)數(shù)據(jù)庫動態(tài)切換了。

審核編輯 黃宇

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

    關注

    7

    文章

    3794

    瀏覽量

    64360
  • mybatis
    +關注

    關注

    0

    文章

    60

    瀏覽量

    6709
收藏 人收藏

    評論

    相關推薦

    lanbview怎么與數(shù)據(jù)庫連接?

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

    labvies訪問數(shù)據(jù)庫

    )是微軟最新的數(shù)據(jù)庫訪問技術,可以用于編寫通過OLE DB 提供者對在數(shù)據(jù)庫服務中的數(shù)據(jù)進行訪問和操作的應用程序。OLE DB 是一個底層的數(shù)據(jù)
    發(fā)表于 08-26 10:19

    LabView動態(tài)創(chuàng)建數(shù)據(jù)源的方法

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

    LabVIEW連接Access數(shù)據(jù)庫的問題

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

    QuickBI助你成為分析師——搞定數(shù)據(jù)源

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

    springboo修改數(shù)據(jù)源為Druid

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

    mybatis支持數(shù)據(jù)庫輕兼容的輕量方案

    一個輕量的方案, 令mybatis支持數(shù)據(jù)庫輕兼容
    發(fā)表于 04-09 17:44

    SpringBoot項目多數(shù)據(jù)源配置數(shù)據(jù)庫

    SpringBoot項目多數(shù)據(jù)源配置
    發(fā)表于 06-05 09:51

    數(shù)據(jù)源配置工具

    odbc_for_access.exe1、可直接配置數(shù)據(jù)源。2、可直接創(chuàng)建Access數(shù)據(jù)庫文件。3、為數(shù)據(jù)庫配置密碼。
    發(fā)表于 07-01 16:22 ?4次下載

    springmvc 自定義攔截器實現(xiàn)未登錄用戶的攔截

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

    數(shù)據(jù)倉庫入門之創(chuàng)建數(shù)據(jù)源

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

    基于Mybatis攔截器實現(xiàn)數(shù)據(jù)范圍權限

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

    如何實現(xiàn)基于Mybatis攔截器實現(xiàn)數(shù)據(jù)范圍權限呢?

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

    多數(shù)據(jù)源數(shù)據(jù)轉換和同步的ETL工具推薦

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

    SpringBoot實現(xiàn)動態(tài)切換數(shù)據(jù)源

    最近在做業(yè)務需求時,需要從不同的數(shù)據(jù)庫中獲取數(shù)據(jù)然后寫入到當前數(shù)據(jù)庫中,因此涉及到切換數(shù)據(jù)源問題。本來想著使用
    的頭像 發(fā)表于 12-08 10:53 ?1013次閱讀
    SpringBoot<b class='flag-5'>實現(xiàn)</b>動態(tài)<b class='flag-5'>切換</b><b class='flag-5'>數(shù)據(jù)源</b>
    主站蜘蛛池模板: 秋霞网韩国理伦片免费看| 女人被躁到高潮嗷嗷叫69| 狠狠色狠狠色综合日日92| 好看的电影网站亚洲一区| 韩国伦理三级| 久久观看视频| 久久天天躁狠狠躁夜夜躁| 娇小亚裔被两个黑人| 九九热精品视频在线观看| 久久精品国产亚洲AV未满十八| 快播电影官方网站| 免费人成视频19674不收费| 日日操日日射| 少妇无套内谢久久久久| 亚洲男人天堂网| 506070老熟肥妇bbwxx视频| 超碰在线97久久视频观看| 国产老师开裆丝袜喷水漫画| 久久不射电影网| 人人啪日日观看在线| 亚洲国语在线视频手机在线| 最近免费视频中文2019完整版| 草莓西瓜樱桃香蕉直播视频| 国内卡一卡二卡三免费网站| 伦理片午夜在线视频| 色屁屁影院| 亚洲综合无码一区二区| caoporn免费视频在线| 国产黄A片在线观看永久免费麻豆 国产互换后人妻的疯狂VIDEO | 欧美狂野乱码一二三四区| 双手绑在床头调教乳尖| 用震蛋调教女性下面视频| 冰山高冷受被c到哭np双性| 好湿好紧水多AAAAA片秀人网| 男人都懂www深夜免费网站| 午夜一级毛片看看| 91久久夜色精品| 国产亚洲精品品视频在线| 欧美末成年videos在线| 亚洲薄码区| 白丝美女被狂躁免费漫画|