成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

MyBatis 源碼閱讀之 databaseId

Donald / 2281人閱讀

摘要:源碼閱讀之的配置文件所有配置會(huì)被類讀取,我們可以通過此類來了解各個(gè)配置是如何運(yùn)作的。是用于項(xiàng)目中存在多種數(shù)據(jù)庫(kù)時(shí)區(qū)分同一條對(duì)應(yīng)的數(shù)據(jù)庫(kù)??梢赃@樣認(rèn)為,在中的和組合才是一條的唯一標(biāo)識(shí)。如果發(fā)現(xiàn)自己的沒被正確識(shí)別,可以查看方法是否和預(yù)期一致。

MyBatis 源碼閱讀之 databaseId

MyBatis 的配置文件所有配置會(huì)被 org.apache.ibatis.builder.xml.XMLConfigBuilder 類讀取,我們可以通過此類來了解各個(gè)配置是如何運(yùn)作的。而 MyBatis 的映射文件配置會(huì)被 org.apache.ibatis.builder.xml.XMLMapperBuilder 類讀取。我們可以通過此類來了解映射文件的配置時(shí)如何被解析的。

databaseId

databaseId 是用于項(xiàng)目中存在多種數(shù)據(jù)庫(kù) SQL 時(shí)區(qū)分同一條 SQL 對(duì)應(yīng)的數(shù)據(jù)庫(kù)??梢赃@樣認(rèn)為,在 Mybatis 中 SQL 的 id 和 databaseId 組合才是一條 SQL 的唯一標(biāo)識(shí)。實(shí)際上 MyBatis 只會(huì)選擇性加載指定 databaseId 的 SQL ,還有一些沒有指定 databaseId 的 SQL。這里說的有點(diǎn)不是很準(zhǔn)確,我們來慢慢分析便可以知曉。

databaseId 的配置

MyBatis 配置文件中 databaseId 的配置如下:



    
    
    

讀取的代碼如下:

private void databaseIdProviderElement(XNode context) throws Exception {
    DatabaseIdProvider databaseIdProvider = null;
    if (context != null) {
        String type = context.getStringAttribute("type");
        // 保持向后兼容
        if ("VENDOR".equals(type)) {
            type = "DB_VENDOR";
        }
        // 屬性設(shè)置
        Properties properties = context.getChildrenAsProperties();
        // 找到 type 配置對(duì)應(yīng)的類
        databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
        databaseIdProvider.setProperties(properties);
    }
    Environment environment = configuration.getEnvironment();
    if (environment != null && databaseIdProvider != null) {
        // 通過數(shù)據(jù)源確定使用的 databaseId ,之后 SQL 也只會(huì)加載這種 databaseId 的 SQL ,其他類型都會(huì)被忽略
        String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
        configuration.setDatabaseId(databaseId);
    }
}

這里的代碼邏輯比較簡(jiǎn)單:

讀取 databaseIdProvider 節(jié)點(diǎn)的 type 值與子節(jié)點(diǎn)屬性值

根據(jù) type 值找到與之匹配的 DatabaseIdProvider 子類,創(chuàng)建相應(yīng)的實(shí)例,將子節(jié)點(diǎn)屬性設(shè)置到實(shí)例中

調(diào)用 DatabaseIdProvider 實(shí)例的 getDatabaseId() 方法獲取值設(shè)置到 Configuration 實(shí)例中

注:

type 為 DB_VENDOR 表示使用 org.apache.ibatis.mapping.VendorDatabaseIdProvider 作為 DatabaseIdProvider 的實(shí)現(xiàn)類。這一點(diǎn)可以在 org.apache.ibatis.session.Configuration 的構(gòu)造方法中找到證據(jù)。

如果發(fā)現(xiàn)自己的 databaseId 沒被正確識(shí)別,可以查看 getDatabaseId() 方法是否和預(yù)期一致。

databaseId 的使用

databaseId 在映射文件里要和上一節(jié)的配置的屬性 value 值對(duì)應(yīng),如下:




    

讀取的代碼在這,這只是 節(jié)點(diǎn)加載的代碼:

private void sqlElement(List list) throws Exception {
    if (configuration.getDatabaseId() != null) {
        // 加載 DataSource 對(duì)應(yīng)的 databaseId 的 SQL 節(jié)點(diǎn)
        sqlElement(list, configuration.getDatabaseId());
    }
    // 記載 databaseId 為空的 SQL 節(jié)點(diǎn)
    sqlElement(list, null);
}

private void sqlElement(List list, String requiredDatabaseId) throws Exception {
    for (XNode context : list) {
        String databaseId = context.getStringAttribute("databaseId");
        String id = context.getStringAttribute("id");
        id = builderAssistant.applyCurrentNamespace(id, false);
        if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
            sqlFragments.put(id, context);
        }
    }
}

private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
    if (requiredDatabaseId != null) {
        if (!requiredDatabaseId.equals(databaseId)) {
            // 兩個(gè) databaseId 一致才會(huì)返回 true,此處不一致
            return false;
        }
    } else {
        // 一個(gè)為空,一個(gè)不為空,也不一致
        if (databaseId != null) {
            return false;
        }

        // 如果先前已經(jīng)加載過節(jié)點(diǎn),則不再加載
        // 是否視為同一個(gè)節(jié)點(diǎn)是由 id 決定
        // 但 id 相同,databaseId 不同 mybatis也可以加載,所以有些地方說,id+databaseId 確定唯一一條 SQL
        if (this.sqlFragments.containsKey(id)) {
            XNode context = this.sqlFragments.get(id);
            if (context.getStringAttribute("databaseId") != null) {
                return false;
            }
        }
    }
    return true;
}

代碼上已經(jīng)有了詳細(xì)的注釋,這里就簡(jiǎn)單說一下。sqlElement() 方法會(huì)被調(diào)用兩次,第一次用于處理 databaseId 與全局 Configuration 實(shí)例的 databaseId 一致的節(jié)點(diǎn);另一次用于處理節(jié)點(diǎn)的 databaseId 為 null 的情況,針對(duì)同一個(gè) id ,優(yōu)先選擇存在 databaseId 并且與數(shù)據(jù)源的一致。

同樣的,