<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
mybatis中有很多實用的註解,但是平時想不起來使用。今天就來講一下MapKey是如何使用的
說明:本文基於mybatis原生框架3.3.0-SNAPSHOT
資料庫準備一張user
表,插入一點測試資料
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;
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介面只有兩個方法queryAll1
queryAll2
。這兩個方法執行的SQL是一樣的,SQL的含義也一樣,就是從user表中取出一條資料。
不同的是
queryAll1
queryAll2
的返回值不一樣queryAll1
沒有使用MapKey註解,返回值是User物件,符合SQL返回的只有一條記錄的語意queryAll2
使用MapKey註解,但是返回值卻是一個Map物件?這似乎不符合SQL返回的語意。SQLselect * from user limit 1
只返回一條記錄。怎麼返回一個Map<String, User>
物件呢?這就是MapKey這個註解的特別之處: 它能夠將存放物件的List轉化為 key值為物件的某一屬性的Map。MapKey有一個屬性value,該屬性值填入的就是物件的屬性名,作為Map的key值。看不懂這句話沒關係,看完執行結果回頭再來看就懂了!使用mybatis的SqlSession獲取Mapper代理物件,分別執行
@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); }
輸出結果
不使用MapKey查詢: User{id=1, username='111', password='222', birthday='333'}
使用MapKey查詢: {111=User{id=1, username='111', password='222', birthday='333'}}
可以看到,新增了MapKey註解的方法執行結果Map的key就是註解裡value值對應的User物件的屬性值。value就是SQL查詢得到的結果User。
這就是MapKey這個註解的特別之處: 它能夠將存放物件的List轉化為 key值為物件的某一屬性的Map。MapKey有一個屬性value,該屬性值填入的就是物件的屬性名,作為Map的key值
現在再來看這句話,是不是就能理解了?
Mapper介面中的方法標註了MapKey後,即使SQL返回多條結果,最終方法返回的結果只有一條。這是因為user表中的username欄位全是一樣的。如果把MapKey註解中的value值改為其他user表中不一樣的欄位,返回結果就會是多條記錄啦
@MapKey("username") @Select("select * from user limit 10") Map<String, User> queryAll5(); @MapKey("id") @Select("select * from user limit 10") Map<String, User> queryAll6();
執行方法
Map<String, User> users5 = userMapper.queryAll5(); System.out.println("users5: " + users5); Map<String, User> users6 = userMapper.queryAll6(); System.out.println("users6: " + users6);
輸出結果
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'}}
如果標註了MapKey,則返回結果Map的value型別不可以是List,否則執行方法會報錯。下面是錯誤範例。
@MapKey("username") // 執行會報錯 @Select("select * from user limit 10") Map<String, List<User>> queryAll5();
@MapKey("username") @Select("select * from user limit 10") Map<String, User> queryAll5();
我們針對如上這個方法進行分析,在執行SQL時會呼叫SqlSession中的如下程式碼
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { //轉而去呼叫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) { //迴圈用DefaultMapResultHandler處理每條記錄 context.nextResultObject(o); mapResultHandler.handleResult(context); } //注意這個DefaultMapResultHandler裡面存了所有已處理的記錄(內部實現可能就是一個Map),最後再返回一個Map return mapResultHandler.getMappedResults(); }
來分析原始碼
select * from user limit 10
,SQL執行的結果返回給List物件,List中確實有10條記錄DefaultMapResultHandler mapResultHandler
,它是用來處理結果集的對映的,呼叫mapResultHandler.handleResult(context);
方法將List結果集中每一條記錄對應Mapkey中的屬性值取出,作為Map的key加入到集合裡。handleResult原始碼如下。其中主要關注這一行就可以了mappedResults.put(key, value);
。
@Override public void handleResult(ResultContext context) { // TODO is that assignment always true? //得到一條記錄 //這邊黃色警告沒法去掉了?因為返回Object型 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); //這個類主要目的是把得到的List轉為Map }
通過handleResult方法原始碼可以看到,對於List結果集中的一條記錄,取出屬性username的值作為Map的key值新增到mappedResults集合中。那麼如果key值相同就會被覆蓋!這就是實戰篇坑1的原理
最後是通過mapResultHandler.getMappedResults();
方法返回第4步中的map最為最終方法的返回值。
MapKey的作用:它能夠將存放物件的List轉化為 key值為物件的某一屬性的Map。MapKey有一個屬性value,該屬性值填入的就是物件的屬性名,作為Map的key值
使用場景:可以針對結果集中的某個屬性去重,而不在乎其他欄位是否重複
以上就是MyBatis的MapKey註解範例解析的詳細內容,更多關於MyBatis MapKey註解的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45