欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis的MapKey注解實(shí)例解析

 更新時(shí)間:2023年02月08日 11:04:02   作者:念念清晰  
這篇文章主要為大家介紹了MyBatis的MapKey注解實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

使用

mybatis中有很多實(shí)用的注解,但是平時(shí)想不起來使用。今天就來講一下MapKey是如何使用的

說明:本文基于mybatis原生框架3.3.0-SNAPSHOT

一、數(shù)據(jù)準(zhǔn)備

數(shù)據(jù)庫準(zhǔn)備一張user表,插入一點(diǎn)測(cè)試數(shù)據(jù)

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `birthday` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1018 DEFAULT CHARSET=utf8mb4
select * from user;

二、Mapper配置

UserMapper接口

public interface UserMapper {
    @Select("select * from user limit 1")
    List<User> queryAll1();
    @MapKey("username")
    @Select("select * from user limit 1")
    Map<String, User> queryAll2();
}

這里我們的mapper接口只有兩個(gè)方法queryAll1 queryAll2。這兩個(gè)方法執(zhí)行的SQL是一樣的,SQL的含義也一樣,就是從user表中取出一條數(shù)據(jù)。

不同的是

  • queryAll1 queryAll2的返回值不一樣
  • queryAll1沒有使用MapKey注解,返回值是User對(duì)象,符合SQL返回的只有一條記錄的語義
  • queryAll2使用MapKey注解,但是返回值卻是一個(gè)Map對(duì)象?這似乎不符合SQL返回的語義。SQLselect * from user limit 1只返回一條記錄。怎么返回一個(gè)Map<String, User>對(duì)象呢?這就是MapKey這個(gè)注解的特別之處: 它能夠?qū)⒋娣艑?duì)象的List轉(zhuǎn)化為 key值為對(duì)象的某一屬性的Map。MapKey有一個(gè)屬性value,該屬性值填入的就是對(duì)象的屬性名,作為Map的key值。看不懂這句話沒關(guān)系,看完執(zhí)行結(jié)果回頭再來看就懂了!

三、實(shí)戰(zhàn)

使用mybatis的SqlSession獲取Mapper代理對(duì)象,分別執(zhí)行

@org.junit.Test
public void testMapKey() throws IOException {
    InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
    SqlSession sqlSession = factory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User users1 = userMapper.queryAll1();
    Map<String, User> users2 = userMapper.queryAll2();
    System.out.println("不使用MapKey查詢: " + users3);
    System.out.println("使用MapKey查詢: " + users4);
}

輸出結(jié)果

不使用MapKey查詢: User{id=1, username='111', password='222', birthday='333'}
使用MapKey查詢: {111=User{id=1, username='111', password='222', birthday='333'}}

可以看到,添加了MapKey注解的方法執(zhí)行結(jié)果Map的key就是注解里value值對(duì)應(yīng)的User對(duì)象的屬性值。value就是SQL查詢得到的結(jié)果User。

這就是MapKey這個(gè)注解的特別之處: 它能夠?qū)⒋娣艑?duì)象的List轉(zhuǎn)化為 key值為對(duì)象的某一屬性的Map。MapKey有一個(gè)屬性value,該屬性值填入的就是對(duì)象的屬性名,作為Map的key值

現(xiàn)在再來看這句話,是不是就能理解了?

實(shí)戰(zhàn)2——注意事項(xiàng)

Mapper接口中的方法標(biāo)注了MapKey后,即使SQL返回多條結(jié)果,最終方法返回的結(jié)果只有一條。這是因?yàn)閡ser表中的username字段全是一樣的。如果把MapKey注解中的value值改為其他user表中不一樣的字段,返回結(jié)果就會(huì)是多條記錄啦

@MapKey("username")
@Select("select * from user limit 10")
Map<String, User> queryAll5();
@MapKey("id")
@Select("select * from user limit 10")
Map<String, User> queryAll6();

執(zhí)行方法

Map<String, User> users5 = userMapper.queryAll5();
System.out.println("users5: " + users5);
Map<String, User> users6 = userMapper.queryAll6();
System.out.println("users6: " + users6);

輸出結(jié)果

users5: {111=User{id=11, username='111', password='222', birthday='333'}}
users6: {1=User{id=1, username='111', password='222', birthday='333'}, 
        3=User{id=3, username='111', password='222', birthday='333'}, 
        4=User{id=4, username='111', password='222', birthday='333'}, 
        5=User{id=5, username='111', password='222', birthday='333'}, 
        6=User{id=6, username='111', password='222', birthday='333'}, 
        7=User{id=7, username='111', password='222', birthday='333'}, 
        8=User{id=8, username='111', password='222', birthday='333'}, 
        9=User{id=9, username='111', password='222', birthday='333'}, 
        10=User{id=10, username='111', password='222', birthday='333'}, 
        11=User{id=11, username='111', password='222', birthday='333'}}

如果標(biāo)注了MapKey,則返回結(jié)果Map的value類型不可以是List,否則執(zhí)行方法會(huì)報(bào)錯(cuò)。下面是錯(cuò)誤示例。

@MapKey("username") // 執(zhí)行會(huì)報(bào)錯(cuò)
@Select("select * from user limit 10")
Map<String, List<User>> queryAll5();

原理

@MapKey("username")
@Select("select * from user limit 10")
Map<String, User> queryAll5();

我們針對(duì)如上這個(gè)方法進(jìn)行分析,在執(zhí)行SQL時(shí)會(huì)調(diào)用SqlSession中的如下代碼

public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
  //轉(zhuǎn)而去調(diào)用selectList
  final List<?> list = selectList(statement, parameter, rowBounds);
  final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<K, V>(mapKey,
      configuration.getObjectFactory(), configuration.getObjectWrapperFactory());
  final DefaultResultContext context = new DefaultResultContext();
  for (Object o : list) {
    //循環(huán)用DefaultMapResultHandler處理每條記錄
    context.nextResultObject(o);
    mapResultHandler.handleResult(context);
  }
  //注意這個(gè)DefaultMapResultHandler里面存了所有已處理的記錄(內(nèi)部實(shí)現(xiàn)可能就是一個(gè)Map),最后再返回一個(gè)Map
  return mapResultHandler.getMappedResults();
}

來分析源碼

  • 使用Executor查詢結(jié)果,這里的SQL是select * from user limit 10,SQL執(zhí)行的結(jié)果返回給List對(duì)象,List中確實(shí)有10條記錄
  • 構(gòu)造一個(gè)對(duì)象DefaultMapResultHandler mapResultHandler,它是用來處理結(jié)果集的映射的,
  • 遍歷第一步中List得到的結(jié)果集對(duì)象

調(diào)用mapResultHandler.handleResult(context);方法將List結(jié)果集中每一條記錄對(duì)應(yīng)Mapkey中的屬性值取出,作為Map的key加入到集合里。handleResult源碼如下。其中主要關(guān)注這一行就可以了mappedResults.put(key, value);。

@Override
public void handleResult(ResultContext context) {
  // TODO is that assignment always true?
  //得到一條記錄
  //這邊黃色警告沒法去掉了?因?yàn)榉祷豋bject型
  final V value = (V) context.getResultObject();
  //MetaObject.forObject,包裝一下記錄
  //MetaObject是用反射來包裝各種類型
  final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory);
  final K key = (K) mo.getValue(mapKey);
  mappedResults.put(key, value);
  //這個(gè)類主要目的是把得到的List轉(zhuǎn)為Map
}

通過handleResult方法源碼可以看到,對(duì)于List結(jié)果集中的一條記錄,取出屬性u(píng)sername的值作為Map的key值添加到mappedResults集合中。那么如果key值相同就會(huì)被覆蓋!這就是實(shí)戰(zhàn)篇坑1的原理

最后是通過mapResultHandler.getMappedResults();方法返回第4步中的map最為最終方法的返回值。

總結(jié)

MapKey的作用:它能夠?qū)⒋娣艑?duì)象的List轉(zhuǎn)化為 key值為對(duì)象的某一屬性的Map。MapKey有一個(gè)屬性value,該屬性值填入的就是對(duì)象的屬性名,作為Map的key值

使用場(chǎng)景:可以針對(duì)結(jié)果集中的某個(gè)屬性去重,而不在乎其他字段是否重復(fù)

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

相關(guān)文章

  • 深度解析SpringBoot中@Async引起的循環(huán)依賴

    深度解析SpringBoot中@Async引起的循環(huán)依賴

    本文主要介紹了深度解析SpringBoot中@Async引起的循環(huán)依賴,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Spring事件Application Event原理詳解

    Spring事件Application Event原理詳解

    這篇文章主要介紹了Spring 事件Application Event原理詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • JavaFX實(shí)現(xiàn)拖拽結(jié)點(diǎn)效果

    JavaFX實(shí)現(xiàn)拖拽結(jié)點(diǎn)效果

    這篇文章主要為大家詳細(xì)介紹了JavaFX實(shí)現(xiàn)拖拽結(jié)點(diǎn)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • idea將maven項(xiàng)目改成Spring boot項(xiàng)目的方法步驟

    idea將maven項(xiàng)目改成Spring boot項(xiàng)目的方法步驟

    這篇文章主要介紹了idea將maven項(xiàng)目改成Spring boot項(xiàng)目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java判斷一個(gè)實(shí)體是不是空的簡(jiǎn)單方法

    Java判斷一個(gè)實(shí)體是不是空的簡(jiǎn)單方法

    這篇文章主要給大家介紹了關(guān)于Java判斷一個(gè)實(shí)體是不是空的簡(jiǎn)單方法,實(shí)際項(xiàng)目中我們會(huì)有很多地方需要判空校驗(yàn),文中給出了詳細(xì)的示例代碼,需要的朋友可以參考下
    2023-07-07
  • Java設(shè)計(jì)模塊系列之書店管理系統(tǒng)單機(jī)版(一)

    Java設(shè)計(jì)模塊系列之書店管理系統(tǒng)單機(jī)版(一)

    這篇文章主要為大家詳細(xì)介紹了Java單機(jī)版的書店管理系統(tǒng)設(shè)計(jì)模塊和思想第一章,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Springboot集成Kafka進(jìn)行批量消費(fèi)及踩坑點(diǎn)

    Springboot集成Kafka進(jìn)行批量消費(fèi)及踩坑點(diǎn)

    本文主要介紹了Springboot集成Kafka進(jìn)行批量消費(fèi)及踩坑點(diǎn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Springboot2 配置AOP日志的方法步驟

    Springboot2 配置AOP日志的方法步驟

    這篇文章主要介紹了Springboot2 配置AOP日志的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • 深入了解HttpClient的ResponseHandler接口

    深入了解HttpClient的ResponseHandler接口

    這篇文章主要為大家介紹了深入了解HttpClient的ResponseHandler接口,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • springboot上傳文件過大的500異常解決

    springboot上傳文件過大的500異常解決

    這篇文章主要介紹了springboot上傳文件過大的500異常解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09

最新評(píng)論