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

MyBatis discriminator標(biāo)簽原理實(shí)例解析

 更新時(shí)間:2023年02月05日 10:56:17   作者:念念清晰  
這篇文章主要為大家介紹了MyBatis discriminator標(biāo)簽實(shí)現(xiàn)原理實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、什么業(yè)務(wù)情況會(huì)使用discriminator標(biāo)簽?

假設(shè)我們有一張user表:

使用查詢語句select * from user有如下需求

當(dāng)用戶年齡為18歲時(shí)查詢結(jié)果顯示生日信息。

當(dāng)用戶年齡不為18歲時(shí)查詢結(jié)果不顯示生日信息。(顯示為空或NULL即可)

如果我們使用mybatis,第一個(gè)想到的解決辦法可能是在Java程序里把用戶信息查出來,然后再根據(jù)年齡做if判斷。但是這樣做有點(diǎn)繁瑣。還好mybatis提供了一個(gè)標(biāo)簽(<discriminator/>)來解決如上的業(yè)務(wù)需求。discriminator也就是偵察器、也叫鑒別器

二、discriminator使用

還是結(jié)合第一節(jié)的業(yè)務(wù)問題來使用discriminator標(biāo)簽

映射文件配置

mapper.xml配置內(nèi)容如下

<resultMap id="userMapForTestDiscriminator" type="user" autoMapping="false">
    <!--關(guān)閉自動(dòng)映射,那么沒有指定的列名不會(huì)出現(xiàn)在結(jié)果集中-->
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="age" column="age"/>
    <discriminator javaType="int" column="age">
        <case value="18" resultType="user">
            <result property="birthday" column="birthday"/>
        </case>
    </discriminator>
</resultMap>
<select id="selectDiscriminator" resultMap="userMapForTestDiscriminator">
    select * from user limit 2
</select>

select標(biāo)簽的id為selectDiscriminator,并且返回結(jié)果集使用resultMap來接收。重點(diǎn)就在resultMap里配置了discriminator。先來解釋一下discriminator的作用:

discriminator有個(gè)子標(biāo)簽是case,并且指定偵察器鑒別的屬性為age。(它的用法很類似于Java中的switch)

當(dāng)查詢的結(jié)果集中age列數(shù)據(jù)等于case指定的value值時(shí)(在這個(gè)例子里就是當(dāng)結(jié)果集中age列為18時(shí))。則把case標(biāo)簽中的result標(biāo)簽加入到外部的resultMap標(biāo)簽中。反之——如果結(jié)果集中的age列值不為18,則不做任何操作。

換個(gè)更直觀的說法來看。

  • 當(dāng)結(jié)果集中的age列等于18時(shí)(本例中)實(shí)際上返回的resultMap標(biāo)簽相當(dāng)于
<resultMap id="userMapForTestDiscriminator" type="user" autoMapping="false">
    <!--關(guān)閉自動(dòng)映射,那么沒有指定的列名不會(huì)出現(xiàn)在結(jié)果集中-->
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="age" column="age"/>
    <result property="birthday" column="birthday"/>
</resultMap>
  • 當(dāng)結(jié)果集中的age列不等于18時(shí)(本例中)實(shí)際上返回的resultMap標(biāo)簽相當(dāng)于
<resultMap id="userMapForTestDiscriminator" type="user" autoMapping="false">
    <!--關(guān)閉自動(dòng)映射,那么沒有指定的列名不會(huì)出現(xiàn)在結(jié)果集中-->
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="age" column="age"/>
</resultMap>

怎么樣?是不是和Java中的Switch用法一模一樣,當(dāng)滿足條件時(shí)就執(zhí)行case語句中的代碼。

Mapper接口配置

public interface UserMapper {
  List<User> selectDiscriminator();
}

測試

@Test
public void test1() throws Exception {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = userMapper.selectDiscriminator();
    for (Object user : users) {
        System.out.println(user);
    }
}

輸出結(jié)果:User(id=1, username=0.620544543088072, age=18, password=222, birthday=2002-10-27, author=null)
User(id=3, username=0.620544543088072, age=22, password=null, birthday=null, author=null)

從輸出結(jié)果中已經(jīng)可以看到,當(dāng)age不等于18的時(shí)候,birthdary字段沒有值。那么mybatis是如何實(shí)現(xiàn)這個(gè)功能的呢?下面來從源碼角度分析下。

總結(jié)

discriminator相當(dāng)于Java中的Switch,作用是可以動(dòng)態(tài)的控制resultMap標(biāo)簽中的result標(biāo)簽。

三、discriminator原理

mybatis初始化的時(shí)候會(huì)加載映射配置文件。

  • 把所有的XxxMapper.xml文件解析為MappedStatement對(duì)象保存在Configuration對(duì)象中。以便于后續(xù)的調(diào)用。
  • 而每個(gè)XxxMapper.xml中的resultMap標(biāo)簽都會(huì)被解析為ResultMap對(duì)象存儲(chǔ)在MappedStatement對(duì)象當(dāng)中
  • ResultMap標(biāo)簽中的每個(gè)discriminator標(biāo)簽都會(huì)被解析為Discriminator對(duì)象存儲(chǔ)在ResultMap對(duì)象當(dāng)中。

至此,Discriminator所在的層級(jí)就是:

下面就從源碼的兩個(gè)方面揭開discriminator的面紗。

初始化時(shí)——加載配置文件并把discriminator標(biāo)簽解析為Discriminator對(duì)象存儲(chǔ)到內(nèi)存中。

執(zhí)行SQL時(shí)——如果檢測到有與該SQL匹配的Discriminator對(duì)象,則調(diào)用Discriminator對(duì)象的邏輯

Discriminator對(duì)象結(jié)構(gòu)

public class Discriminator {
  private ResultMapping resultMapping;
  private Map<String, String> discriminatorMap;
}

Discriminator對(duì)象有兩個(gè)字段

  • resultMapping記錄的是<discriminator javaType="int" column="age">中的age字段的相關(guān)信息(列名、jdbc類型、Java類型、是否嵌套等等??傊涗浀氖氰b別器鑒別的那個(gè)列的列信息。而這個(gè)信息被封裝成了ResultMapping對(duì)象,比較簡單感興趣的可以看下ResultMapping對(duì)象源碼)
  • discriminatorMap記錄的是<case value="18" resultType="user">case標(biāo)簽的信息。它是一個(gè)map結(jié)構(gòu),key是case中value屬性的值,value是resultmap的的唯一標(biāo)識(shí)。(mybatis會(huì)通過resultMap的唯一標(biāo)識(shí)去configuration對(duì)象中尋找對(duì)應(yīng)的resultMap)

初始化

看到這里,默認(rèn)讀者有看過一定的mybatis源碼。mybatis在啟動(dòng)時(shí)通過XMLMapperBuilder來加載映射文件(xml文件)。其中包含了對(duì)ResultMap標(biāo)簽的解析過程。具體邏輯在XMLMapperBuilder#resultMapElement方法中。代碼如下(只列出了有關(guān)Discriminator的邏輯)

private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) {
    // 1. 解析配置文件的標(biāo)簽創(chuàng)建為Discriminator對(duì)象
    Discriminator discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
    // 2. 構(gòu)建ResultMapResolver對(duì)象,再調(diào)用resolve方法創(chuàng)建ResultMap對(duì)象,Discriminator就是在resolve方法中被ResultMap對(duì)象中的
    // 說白了是構(gòu)建ResultMap的輔助類。
    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    return resultMapResolver.resolve();
}

調(diào)用processDiscriminatorElement方法為Discriminator對(duì)象設(shè)置詳細(xì)的屬性。

private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) {
  // 通過 column javaType jdbcType typeHandler javaTypeClass typeHandlerClass 
  // 來構(gòu)造Discriminator對(duì)象中的resultMapping字段
  String column = context.getStringAttribute("column");
  String javaType = context.getStringAttribute("javaType");
  String jdbcType = context.getStringAttribute("jdbcType");
  String typeHandler = context.getStringAttribute("typeHandler");
  Class<?> javaTypeClass = resolveClass(javaType);
  Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
  JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
  Map<String, String> discriminatorMap = new HashMap<>();
  // 遍歷discriminator標(biāo)簽,把case節(jié)點(diǎn)的信息封裝為Discriminator對(duì)象中的discriminatorMap字段
  for (XNode caseChild : context.getChildren()) {
    String value = caseChild.getStringAttribute("value");
    String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings, resultType));
    discriminatorMap.put(value, resultMap);
  }
  // 調(diào)用輔助類整整的構(gòu)建Discriminator對(duì)象
  return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
}

至此,Discriminator對(duì)象就被完整的創(chuàng)建出來了。它會(huì)被添加在ResultMap對(duì)象中緩存。后續(xù)程序執(zhí)行過程中,就能通過Configuration對(duì)象獲取MappedStatement對(duì)象,再通過MappedStatement對(duì)象獲取ResultMap對(duì)象,再通過ResultMap對(duì)象就可以獲取Discriminator對(duì)象啦!

需要注意的是,每個(gè)case標(biāo)簽都會(huì)被解析為一個(gè)結(jié)果集間接存入到configuration對(duì)象中。

執(zhí)行SQL時(shí)

在程序通過mybatis執(zhí)行數(shù)據(jù)庫操作時(shí),會(huì)通過ResultSetHandler對(duì)象來處理數(shù)據(jù)庫返回的結(jié)果集。ResultSetHandler是mybatis的幾個(gè)核心對(duì)象之一。它在DefaultResultSetHandler#resolveDiscriminatedResultMap方法中進(jìn)行對(duì)Discriminator的邏輯處理。方法代碼如下

public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
  // 1 通過resultMap獲取鑒別器對(duì)象Discriminator
  Discriminator discriminator = resultMap.getDiscriminator();
  while (discriminator != null) {
    // 2. 從鑒別器中獲取結(jié)果集中對(duì)應(yīng)的需要被鑒別的值。拿文章開頭的業(yè)務(wù)舉例,在此就是獲取結(jié)果集中的age列的值,第一行age的值是18。也就是value的值為18。第二行age的值為22
    final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
    final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
    // 3. 判斷configuration對(duì)象中是否有指定的resultMap對(duì)象,后面會(huì)根據(jù)這個(gè)resultMap進(jìn)行映射結(jié)果集
    if (configuration.hasResultMap(discriminatedMapId)) {
      resultMap = configuration.getResultMap(discriminatedMapId);
    }
  }
  return resultMap;
}

代碼邏輯的大致步驟如下

  • 通過resultMap獲取鑒別器對(duì)象Discriminator
  • 從鑒別器中獲取結(jié)果集中對(duì)應(yīng)的需要被鑒別的值。拿文章開頭的業(yè)務(wù)舉例,在此就是獲取結(jié)果集中的age列的值,第一行age的值是18。也就是value的值為18。第二行age的值為22
  • 獲取case中的值,在本例中case會(huì)拿age的值和18做比較,如果比較不相等則不做處理,否則會(huì)把對(duì)應(yīng)的resultMap的值返回,交給ResultSetHandler去處理映射關(guān)系。

以上就是MyBatis discriminator標(biāo)簽原理實(shí)例解析的詳細(xì)內(nèi)容,更多關(guān)于MyBatis discriminator標(biāo)簽的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java線程池submit阻塞獲取結(jié)果的實(shí)現(xiàn)原理詳解

    Java線程池submit阻塞獲取結(jié)果的實(shí)現(xiàn)原理詳解

    Java線程池中提交任務(wù)運(yùn)行,通常使用execute()方法就足夠了。那如果想要實(shí)現(xiàn)在主線程中阻塞獲取線程池任務(wù)運(yùn)行的結(jié)果,該怎么辦呢?本文就來和大家一起討論討論
    2022-10-10
  • Java通過cellstyle屬性設(shè)置Excel單元格常用樣式的全面總結(jié)講解

    Java通過cellstyle屬性設(shè)置Excel單元格常用樣式的全面總結(jié)講解

    在處理Excel文件時(shí),經(jīng)常需要對(duì)單元格進(jìn)行樣式設(shè)置,以滿足特定的需求和美化要求,這篇文章主要給大家介紹了關(guān)于Java通過cellstyle屬性設(shè)置Excel單元格常用樣式的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • idea中項(xiàng)目文件目錄消失如何解決

    idea中項(xiàng)目文件目錄消失如何解決

    這篇文章主要介紹了idea中項(xiàng)目文件目錄消失的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 使用SpringBoot整合Jpa的過程詳解

    使用SpringBoot整合Jpa的過程詳解

    SpringBoot是一種快速開發(fā)框架,它簡化了Java應(yīng)用程序的開發(fā)過程,而Jpa是Java持久化規(guī)范的一種實(shí)現(xiàn),將SpringBoot與Jpa整合可以更加方便地進(jìn)行數(shù)據(jù)庫操作,提高開發(fā)效率,本文將介紹如何使用Spring Boot整合Jpa,幫助讀者快速上手并應(yīng)用于實(shí)際項(xiàng)目中
    2023-12-12
  • Spring中屬性文件properties的讀取與使用詳解

    Spring中屬性文件properties的讀取與使用詳解

    這篇文章主要介紹了Spring中屬性文件properties的讀取與使用詳解的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Java延遲隊(duì)列原理與用法實(shí)例詳解

    Java延遲隊(duì)列原理與用法實(shí)例詳解

    這篇文章主要介紹了Java延遲隊(duì)列原理與用法,結(jié)合實(shí)例形式詳細(xì)分析了延遲隊(duì)列的概念、原理、功能及具體使用方法,需要的朋友可以參考下
    2018-09-09
  • java.lang.ArrayStoreException異常的解決方案

    java.lang.ArrayStoreException異常的解決方案

    這篇文章主要介紹了java.lang.ArrayStoreException異常的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java注解的簡單入門小案例

    Java注解的簡單入門小案例

    這篇文章主要介紹了Java注解的簡單入門小案例,注解是干什么的?怎么使用?注解的簡單用法,需要的朋友可以參考下
    2023-04-04
  • Java線程的相關(guān)方法詳細(xì)解析

    Java線程的相關(guān)方法詳細(xì)解析

    以下是對(duì)Java線程的相關(guān)方法進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下
    2013-09-09
  • java去除空格、標(biāo)點(diǎn)符號(hào)的方法實(shí)例

    java去除空格、標(biāo)點(diǎn)符號(hào)的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于java去除空格、標(biāo)點(diǎn)符號(hào)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09

最新評(píng)論

玉田县| 中阳县| 兴安盟| 德保县| 平罗县| 杭州市| 福贡县| 锦州市| 辽中县| 邢台市| 浦城县| 桐乡市| 怀来县| 秦皇岛市| 绍兴市| 遂昌县| 巨野县| 漳浦县| 多伦县| 延川县| 巴中市| 金门县| 阿克| 吴旗县| 丽江市| 柳江县| 恩施市| 合肥市| 三都| 德江县| 许昌县| 江都市| 上犹县| 股票| 灵山县| 徐汇区| 迁安市| 红原县| 滕州市| 建水县| 安新县|