国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

MyBatis 源碼閱讀之 databaseId

Donald / 2232人閱讀

摘要:源碼閱讀之的配置文件所有配置會被類讀取,我們可以通過此類來了解各個配置是如何運作的。是用于項目中存在多種數據庫時區分同一條對應的數據庫。可以這樣認為,在中的和組合才是一條的唯一標識。如果發現自己的沒被正確識別,可以查看方法是否和預期一致。

MyBatis 源碼閱讀之 databaseId

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

databaseId

databaseId 是用于項目中存在多種數據庫 SQL 時區分同一條 SQL 對應的數據庫。可以這樣認為,在 Mybatis 中 SQL 的 id 和 databaseId 組合才是一條 SQL 的唯一標識。實際上 MyBatis 只會選擇性加載指定 databaseId 的 SQL ,還有一些沒有指定 databaseId 的 SQL。這里說的有點不是很準確,我們來慢慢分析便可以知曉。

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";
        }
        // 屬性設置
        Properties properties = context.getChildrenAsProperties();
        // 找到 type 配置對應的類
        databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
        databaseIdProvider.setProperties(properties);
    }
    Environment environment = configuration.getEnvironment();
    if (environment != null && databaseIdProvider != null) {
        // 通過數據源確定使用的 databaseId ,之后 SQL 也只會加載這種 databaseId 的 SQL ,其他類型都會被忽略
        String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
        configuration.setDatabaseId(databaseId);
    }
}

這里的代碼邏輯比較簡單:

讀取 databaseIdProvider 節點的 type 值與子節點屬性值

根據 type 值找到與之匹配的 DatabaseIdProvider 子類,創建相應的實例,將子節點屬性設置到實例中

調用 DatabaseIdProvider 實例的 getDatabaseId() 方法獲取值設置到 Configuration 實例中

注:

type 為 DB_VENDOR 表示使用 org.apache.ibatis.mapping.VendorDatabaseIdProvider 作為 DatabaseIdProvider 的實現類。這一點可以在 org.apache.ibatis.session.Configuration 的構造方法中找到證據。

如果發現自己的 databaseId 沒被正確識別,可以查看 getDatabaseId() 方法是否和預期一致。

databaseId 的使用

databaseId 在映射文件里要和上一節的配置的屬性 value 值對應,如下:




    

讀取的代碼在這,這只是 節點加載的代碼:

private void sqlElement(List list) throws Exception {
    if (configuration.getDatabaseId() != null) {
        // 加載 DataSource 對應的 databaseId 的 SQL 節點
        sqlElement(list, configuration.getDatabaseId());
    }
    // 記載 databaseId 為空的 SQL 節點
    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)) {
            // 兩個 databaseId 一致才會返回 true,此處不一致
            return false;
        }
    } else {
        // 一個為空,一個不為空,也不一致
        if (databaseId != null) {
            return false;
        }

        // 如果先前已經加載過節點,則不再加載
        // 是否視為同一個節點是由 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;
}

代碼上已經有了詳細的注釋,這里就簡單說一下。sqlElement() 方法會被調用兩次,第一次用于處理 databaseId 與全局 Configuration 實例的 databaseId 一致的節點;另一次用于處理節點的 databaseId 為 null 的情況,針對同一個 id ,優先選擇存在 databaseId 并且與數據源的一致。

同樣的,