您好,登錄后才能下訂單哦!
這篇文章主要介紹如何實(shí)現(xiàn)Mybatis返回單個(gè)實(shí)體或者返回List,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
Mybatis 的強(qiáng)大之處之一體現(xiàn)在映射語句上,讓我們可以使用簡單的配置,就可以實(shí)現(xiàn)對(duì)參數(shù)和返回結(jié)果的映射。
實(shí)體
package com.test.User public class User{ private String userId; private String userName; private String userPassword; private Date createTime; ... setter getter.... }
DAO
public interface UserMapper{ User getUserById(String userId); //返回單個(gè)實(shí)體 List<User> getUserByName(String userName); //返回List Map<String,Object> getUserInfoById(String userId); List<Map<String,Object>> getUserInfoByName(String userName); }
數(shù)據(jù)庫
create table user{ USER_ID varchar(40), USER_NAME varchar(200), USER_PASSWORD varchar(100), CREATE_TIME datetime, .... }
1.返回某個(gè)實(shí)體
mybatis映射文件
<select id="getUserById" parameterType="string" resultType="com.test.User"> select * from user where id = #{userId} </select>
當(dāng)使用resultType來映射結(jié)果時(shí),需要 數(shù)據(jù)庫表的列名或列別名 和 類的屬性名相同,這樣才能進(jìn)行字段的匹配(USER_ID 和userId 就不能匹配)。但是如果在Mybatis配置文件中設(shè)置了
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> <!--開啟自動(dòng)駝峰命名規(guī)則(camel case)映射,即從經(jīng)典數(shù)據(jù)庫列名 A_COLUMN 到經(jīng)典 Java 屬性名 aColumn 的類似映射。--> </settings>
此時(shí),表列名的下劃線標(biāo)記方式可以映射到駝峰標(biāo)記的形式。(USER_ID -> userId)。mybatis進(jìn)行映射時(shí)會(huì)將實(shí)體類屬性和數(shù)據(jù)庫列名(別名)都轉(zhuǎn)化為大寫來比較,所以USER_ID 和 UserId,userID等都可以匹配。
TooManyResultsException
返回單個(gè)實(shí)體時(shí),調(diào)用方法 getUserById
,但是如果是因?yàn)閿?shù)據(jù)錯(cuò)誤導(dǎo)致實(shí)際查詢結(jié)果存在多個(gè)時(shí),則會(huì)拋出異常。
User getUserById(String userId); //返回單個(gè)實(shí)體
當(dāng)實(shí)際返回值有多個(gè)時(shí)則拋出異常。
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 2
除非可以確定最多只能查詢到一條結(jié)果,否則的話不建議這么寫.可以嘗試返回集合的方式。
2.返回List<entityName>
<select id="getUserByName" resultType="com.test.User"> select * from user where user_name = #{userName} </select>
返回List<T> 集合時(shí),resultType設(shè)置為集合元素的類型即T。然后使用返回幾何數(shù)據(jù)的Mapper方法即可。
List<User> getUserByName(String userName); //返回List
從上面可以看到,返回單個(gè)實(shí)體與返回集合的resultType指定類型是一樣的,不一樣的地方在Mapper接口或者sqlSession中定義的返回結(jié)果類型。實(shí)際上mybatis執(zhí)行查詢的時(shí)候也都是使用sqlSession.selectList()來進(jìn)行查詢的。
推薦使用返回List的方式來查詢結(jié)果
//查詢單條結(jié)果 List<User> userList= mapper.getUserByName(userName); if(userList.isEmpty() || userList.size() >1)//期望獲得一條結(jié)果 //業(yè)務(wù)處理,一般是拋出異?;蛘咧苯臃祷劐e(cuò)誤結(jié)果 //return xx; //throw xxx User user = userList.get(0);
擴(kuò)展
為什么查詢單條和查詢多條使用的是相同的resultType
,而返回的結(jié)果不同呢。
這是因?yàn)镸ybatis 在內(nèi)部進(jìn)行數(shù)據(jù)查詢的時(shí),無論查詢單條還是多條都是通過selectList
實(shí)現(xiàn)的,不同的是查詢單條Mybatis會(huì)獲取第一條,并且如果結(jié)果中存在多條時(shí)拋出異常 TooManyResultsException
。
查詢單數(shù)據(jù)
@Override public <T> T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. List<T> list = this.<T>selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } else if (list.size() > 1) { throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); } else { return null; } }
查詢列表
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) { List<E> result; Object param = method.convertArgsToSqlCommandParam(args); if (method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); result = sqlSession.<E>selectList(command.getName(), param, rowBounds); } else { result = sqlSession.<E>selectList(command.getName(), param); } // issue #510 Collections & arrays support if (!method.getReturnType().isAssignableFrom(result.getClass())) { if (method.getReturnType().isArray()) { return convertToArray(result); } else { return convertToDeclaredCollection(sqlSession.getConfiguration(), result); } } return result; }
那么Mybatis怎么知道是查詢的單條數(shù)據(jù)還是列表呢?
selectOne
還是 selectList
解析方法中的參數(shù)、返回值
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) { Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface); if (resolvedReturnType instanceof Class<?>) { this.returnType = (Class<?>) resolvedReturnType; } else if (resolvedReturnType instanceof ParameterizedType) { this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType(); } else { this.returnType = method.getReturnType(); } this.returnsVoid = void.class.equals(this.returnType); this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray()); this.returnsCursor = Cursor.class.equals(this.returnType); this.mapKey = getMapKey(method); this.returnsMap = (this.mapKey != null); this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class); this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class); this.paramNameResolver = new ParamNameResolver(configuration, method); }
method
對(duì)象就是 Mapper中的方法
// select 查詢操作 case SELECT: // 方法中沒有定義返回結(jié)果,并且方法存在結(jié)果處理器 if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { // 返回列表 result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { // 返回Map result = executeForMap(sqlSession, args); } else if (method.returnsCursor()) { // 返回游標(biāo) result = executeForCursor(sqlSession, args); } else { // 返回單條數(shù)據(jù) Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); } break;
3.返回Map
返回map 本質(zhì)上也是返回一個(gè)實(shí)體。
<select id="getUserInfoById" resultType="map"> select * from user where id=#{userId} </select>
如果想要返回單個(gè)Map<key,value>集合,只需要設(shè)置resultType="map"
就可以了,此時(shí)返回的實(shí)例類型是HashMap。
Map的key就是數(shù)據(jù)表的列名
或者列別名
, value 就是查詢的數(shù)據(jù)庫中的結(jié)果。如果需要返回LinkedHashMap,需要使用全限定類名resultType="java.util.LinkedHashMap"
。
注意: 返回列對(duì)應(yīng)的結(jié)果為 null
,則不顯示該 key - value 鍵值對(duì)(只針對(duì)該行數(shù)據(jù)對(duì)應(yīng)的Map)
<select id="getUserInfoById" resultType="map"> select * from user where id=#{userId} </select>
在Oracle
環(huán)境下:
最終返回Map:
{"name ":"全部"} // code 不是顯示
如果使用map接受則不會(huì)該map不存在數(shù)據(jù). 因?yàn)镸ybatis默認(rèn)情況下,不會(huì)進(jìn)行賦值,此時(shí)該key-value
缺失
如果需要改變該行為可以在mybatis配置文件中設(shè)置
<setting name="callSettersOnNulls" value="true"/>
callSettersOnNulls指定當(dāng)返回結(jié)果為null 的時(shí)候是否調(diào)用映射對(duì)象的 setter(map 對(duì)象時(shí)為 put)方法,注意基本類型(int、boolean等)是不能設(shè)置成 null 的。
配置之后的返回結(jié)果:
{"code":null,"name":"全部"}
4.返回List<Map>
<select id="" parameterType="" resultType="map"> sql_caluse </select>
resultType設(shè)置為map,跟上面一樣resultType設(shè)置為List集合中元素的類型。
關(guān)于mybatis傳遞多個(gè)參數(shù),可以參考mybatis3-傳遞多參數(shù)
注意:
偶然發(fā)現(xiàn)Mybatis 會(huì)自動(dòng)對(duì)重名的列做去重。
比如我有一組數(shù)據(jù),使用Map接受
SELECT l1.*,l2.*,l3.* FROM ITEM_CAT l1 LEFT JOIN ITEM_CAT l2 ON l1.Id=L2.PARENT_ID LEFT JOIN ITEM_CAT l3 ON l2.Id=L3.PARENT_ID WHERE L1.PARENT_ID='0';
實(shí)際返回結(jié)果,會(huì)發(fā)現(xiàn) name1,name2 都沒有映射到Map中
[ {"parent_id":0,"name":"圖書","id":1}, {"parent_id":0,"name":"圖書","id":1}, {"parent_id":0,"name":"圖書","id":1}, {"parent_id":0,"name":"圖書","id":1} ...... ]
稍微修改一下字段名稱。
SELECT l1.*,l2.*,l3.*,'test' as name1 FROM ITEM_CAT l1 LEFT JOIN ITEM_CAT l2 ON l1.Id=L2.PARENT_ID LEFT JOIN ITEM_CAT l3 ON l2.Id=L3.PARENT_ID WHERE L1.PARENT_ID='0';
[ {"parent_id":0,"name":"圖書","id":1,"name1":"test"}, {"parent_id":0,"name":"圖書","id":1,"name1":"test"}, {"parent_id":0,"name":"圖書","id":1,"name1":"test"}, {"parent_id":0,"name":"圖書","id":1,"name1":"test"} ...... ]
可以看到 新增的自定義列名 “name1”,可以正常顯示。這是因?yàn)槭褂胹ql 查詢出的同名的列名自動(dòng)追加數(shù)字做區(qū)分,而實(shí)際保存在 元數(shù)據(jù)信息中的列名還是原來的。就如同Excel 的單元格一樣,不管單元格內(nèi)容以什么樣式顯示都不會(huì)修改實(shí)際值。
小結(jié):
返回結(jié)果 | Mapper | xml |
---|---|---|
實(shí)體 | T getT() | returnType=“T” |
集合 | List<T> getTList() | returnType=“T” |
以上是如何實(shí)現(xiàn)Mybatis返回單個(gè)實(shí)體或者返回List的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。