官方說明文檔:http://www.mybatis.org/mybatis-3/zh/index.html#
resultType和resultMap區(qū)別
resultType:從這條語句中返回的期望類型的類的完全限定名或別名。注意如果是集合情形,那應(yīng)該是集合可以包含的類型,而不能是集合本身。使用 resultType 或 resultMap,但不能同時使用。
也就是說,使用resultType直接表示的就是返回類型,可以是基本類型(int、string)、list、map這些,也可以是具體的pojo對象
- 完全限定名,意思是例如返回Task對象,那么值填寫的是該Task類的完整類路徑;如果返回的是基礎(chǔ)類型,就是類似java.util.Map
- 別名,意思是例如返回map類型,我們不需要寫完整的java.util.Map,可以用map替代
- 不能是集合本身,這句話意思是例如接口需要返回List<Task>,那么直接寫resultType="com.baidu.vo.Task",而不是寫成resultType="List<com.baidu.vo.Task>"
resultMap:外部 resultMap 的命名引用。結(jié)果集的映射是 MyBatis 最強大的特性,對其有一個很好的理解的話,許多復(fù)雜映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同時使用。
相對復(fù)雜一點,需要先定義一個外部標(biāo)簽<resultMap>,這里面一般定義了結(jié)果到pojo的映射關(guān)系,有id屬性,在具體的查詢語句中通過id尋找對應(yīng)的resultMap
- 外部 resultMap 的命名引用,意思是并不是直接的返回類型,只是一個引用標(biāo)識,需要去找對應(yīng)的該引用的定義地方
DEMO-resultType
- select * from task where id = {id} 輸出單個Task對象
TaskMapper.xml代碼
<select id="select" parameterType="int" resultType="com.baidu.pojo.entity.Task">
select * from task where id = #{id}
</select>
TaskMapper.java代碼
Task select(int id);
- select * from task 輸出Task集合
TaskMapper.xml代碼
<select id="select" resultType="com.baidu.pojo.entity.Task">
select * from task
</select>
TaskMapper.java代碼
List<Task> select();
note:通過上面兩個例子發(fā)現(xiàn),無論輸出單個對象還是一個列表,resultType的類型都是一樣的。如果第二個例子中,TaskMapper.java里面方法返回值類型是Task而不是List<Task>的話,當(dāng)查詢的結(jié)果包含多條語句時,就會拋TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 10
- select count(*) from task
TaskMapper.xml代碼
<select id="select" resultType="int">
select count(*) from task
</select>
TaskMapper.java代碼
int select();
- select name from task where id = {id} 輸出單個name
TaskMapper.xml代碼
<select id="select" parameterType="int" resultType="String">
select name from task where id = #{id}
</select>
TaskMapper.java代碼
String select(int id);
- select distinct name from task 輸出name集合
TaskMapper.xml代碼
<select id="select" resultType="String">
select distinct name from task
</select>
TaskMapper.java代碼
List<String> select();
note:無論是單個name還是一個name集合,resultType都是String
- select id, name from task where id = {id}
TaskMapper.xml代碼
<select id="select" resultType="map">
select id, name from task where id = #{id}
</select>
TaskMapper.java代碼
Map select();
note:返回類型是map時,一條記錄會映射為一個map對象,列名對應(yīng)鍵,結(jié)果對應(yīng)值,如果是多條結(jié)果,那么應(yīng)該映射為類型的map的一個集合
- select status, count(*) as num from task group by status desc 統(tǒng)計任務(wù)表里所有狀態(tài)的個數(shù)
TaskMapper.xml代碼
<select id="select" resultType="hashmap">
select status, count(*) as num from task group by status desc
</select>
TaskMapper.java代碼
List<HashMap> select();
note:注意這里的返回值是一個list,list中的元素是map對象,假如group之后有4組,那么就是包含4個map的數(shù)組
- select * from task where id in (3, 4, 5) 參數(shù)是一個數(shù)組
TaskMapper.xml代碼
<select id="select" resultType="com.baidu.pojo.entity.Task">
select * from task where id in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
TaskMapper.java代碼
List<Task> select(List ids);
note:item代表循環(huán)中的具體對象,如果collection屬性是list,那item就表示list中的一個元素;collection是遍歷的對象,可以是list、array,如果Mapper.java里傳入?yún)?shù)時使用@param(“param”)來設(shè)置名字,那這里的collection屬性就填寫對應(yīng)的參數(shù)名;separator是分隔符,例如sql中出現(xiàn)in語句時,就會設(shè)置separator=“,”分隔;open和close代表in語句里面的前后括號
- insert into task (title, name) values ('標(biāo)題', '名字') 參數(shù)是一個map
TaskMapper.xml代碼
<insert id="insert" parameterType="map">
insert into task
<foreach collection="map.keys" item="key" open="(" close=")" separator=",">
${key}
</foreach>
values
<foreach collection="map.keys" item="key" open="(" close=")" separator=",">
#{map[${key}]}
</foreach>
</insert>
TaskMapper.java代碼
int test(@Param("map") Map map);
note:這里Mapper.java文件里面使用的@param注解,對應(yīng)的collection就使用注解定義好的名字
DEMO-resultMap
定義一個Task類
public class Task {
private Integer id;
private String title;
private String name;
private Date createAt;
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Date getCreateAt() {return createAt;}
public void setCreateAt(Date createAt) {this.createAt = createAt;}
}
定義一個resultMap
<resultMap id="BaseResultMap" type="com.baidu.pojo.entity.Task">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="title" property="title" jdbcType="VARCHAR"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="create_at" property="createAt" jdbcType="TIMESTAMP"/>
</resultMap>
note:column代表數(shù)據(jù)庫表里面的屬性,property代表賦值給實體對象的屬性
定義一個sql
<sql id="Base_Column_List">
id, title, name, create_at
</sql>
note:這個元素是用來定義可以重復(fù)使用的sql代碼語句的,這里面把Task表的全部列名定義為了一個sql,是為了下面查詢語句的重復(fù)使用
- select * from task where create_at = '2017-07-07' 查詢數(shù)據(jù)
TaskMapper.xml代碼
<select id="select" resultMap="BaseResultMap" parameterType="com.baidu.pojo.entity.Task">
select <include refid="Base_Column_List"/> from task
<where>
<if test="id != null">id=#{id}</if>
<if test="title != null">and title=#{title}</if>
<if test="name != null">and name=#{name}</if>
<if test="createAt != null">and create_at=#{createAt}</if>
</where>
</select>
TaskMapper.java代碼
List<Task> select(Task task);
note:這里用到了resultMap屬性,where元素知道只有在一個以上的if條件有值的情況下才去插入WHERE子句。而且,若最后的內(nèi)容是AND或OR開頭的,where元素也知道如何將他們?nèi)コ?。這里面的if語句很直觀,就是代表如果傳入的參數(shù)中,該屬性不為空,那么就把該條件帶上去
- insert into task (title, name,create_at) values ('標(biāo)題', '名字', '2017-07-07') 插入數(shù)據(jù)
TaskMapper.xml代碼
<insert id="add" parameterType="com.baidu.pojo.entity.Task" useGeneratedKeys="true" keyProperty="id">
insert into task (<include refid="Base_Column_List"/>) values (
#{id,jdbcType=INTEGER},
#{title,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR},
#{createAt,jdbcType=TIMESTAMP} )
</insert>
TaskMapper.java代碼
int add(Task task);
note:useGeneratedKeys表示是否使用JDBC的getGenereatedKeys方法獲取主鍵并賦值到keyProperty設(shè)置的屬性中,這里就是id是自增長的主鍵,值可以通過getGenereatedKeys方法獲取然后復(fù)制到task對象的屬性上面
- update task set name = '名字' where id = {id} 更新數(shù)據(jù)
TaskMapper.xml代碼
<update id="update" parameterType="com.baidu.pojo.entity.Task">
update task
<set>
<if test="title != null">title=#{title,jdbcType=VARCHAR},</if>
<if test="name != null">name=#{name,jdbcType= VARCHAR},</if>
<if test="createAt != null">create_at=#{createAt,jdbcType=TIMESTAMP}</if>
</set>
</update>
TaskMapper.java代碼
int update(Task task);
note:set 元素會動態(tài)前置SET關(guān)鍵字,同時也會消除無關(guān)的逗號
- delete from task where create_at = '2017-07-07' 刪除數(shù)據(jù)
TaskMapper.xml代碼
<delete id="select" parameterType="com.baidu.pojo.entity.Task">
delete from task
<where>
<if test="id != null">id=#{id}</if>
<if test="title != null">and title=#{title}</if>
<if test="name != null">and name=#{name}</if>
<if test="createAt != null">and create_at=#{createAt}</if>
</where>
</delete>
TaskMapper.java代碼
int delete(Task task);
- select * from task where title = {title} and name = {name} 利用索引傳遞多個參數(shù)
TaskMapper.xml代碼
<select id="select" resultMap="baseResultMap">
select <include refid="Base_Column_List"/> from task where title = #{0} and name = #{1}
</select>
TaskMapper.java代碼
List<Task> select(String title, String name);
note:使用#{index}指定參數(shù),索引從0開始
- select * from task where title = {title} and name = {name} 利用@param注解傳遞多個參數(shù)
TaskMapper.xml代碼
<select id="select" resultMap="baseResultMap">
select <include refid="Base_Column_List"/> from task where title = #{title} and name = #{name}
</select>
TaskMapper.java代碼
List<Task> select(@Param("title") String title, @Param("name") String name);
DEMO-關(guān)聯(lián)查詢
描述:一個計劃有一個執(zhí)行人,一個人只能執(zhí)行一個計劃
定義一個User類
public class User {
private Integer id;
private String name;
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
定義一個Plan類
public class Plan {
private Integer id;
private String name;
private User user;
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getUser() {return user;}
public void setUser(User user) {this. user = user;}
}
- select * from plan, user where plan.uid = user.id and plan.id = #{id} 一對一關(guān)聯(lián)查詢(方式一)
定義一個resultMap
<resultMap id="PlanUserMap" type="com.baidu.pojo.entity.Plan">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<association property="user" javaType="com.baidu.pojo.entity.User">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
</association>
</resultMap>
PlanMapper.xml代碼
<select id="select" parameterType="int" resultMap="PlanUserMap">
select * from plan, user where plan.uid = user.id and plan.id = #{id}
</select>
PlanMapper.java代碼
Plan select(int id);
note:uid是Task表的外鍵,這里面用的是association標(biāo)簽
- select * from plan, user where plan.uid = user.id and plan.id = #{id} 一對一關(guān)聯(lián)查詢(方式二)
定義一個resultMap
<resultMap id="PlanUserMap" type="com.baidu.pojo.entity.Plan">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<association column="uid" property="user" select="getUser"/>
</resultMap>
PlanMapper.xml代碼
<select id="select" parameterType="int" resultMap="PlanUserMap">
select * from plan where id = #{id}
</select>
<select id="getUser" parameterType="int" resultType="com.baidu.pojo.entity.User">
select * from user where id = #{id}
</select>
PlanMapper.java代碼
Plan select(int id);
note:先查詢出一條Plan記錄,然后把該記錄的uid值作為User表的id,查詢對應(yīng)的User記錄
描述:一個計劃可以執(zhí)行多個任務(wù),一個任務(wù)屬于一個計劃
定義一個Task類
public class Task {
private Integer id;
private String title;
private String name;
private Date createAt;
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Date getCreateAt() {return createAt;}
public void setCreateAt(Date createAt) {this.createAt = createAt;}
}
定義一個Plan類
public class Plan {
private Integer id;
private String name;
private List<Task> tasks;
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public List<Task> getTasks() {return tasks;}
public void setTasks(List<Task> tasks) {this. tasks = tasks;}
}
- select * from plan, task where plan.id = task.pid and plan.id = #{id} 一對多關(guān)聯(lián)查詢(方式一)
定義一個resultMap
<resultMap id="PlanTaskMap" type="com.baidu.pojo.entity.Plan">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<collection property="tasks" ofType="com.baidu.pojo.entity.Task">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="title" property="title" jdbcType="VARCHAR"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="create_at" property="createAt" jdbcType="TIMASTAMP"/>
</collection>
</resultMap>
PlanMapper.xml代碼
<select id="select" parameterType="int" resultMap="PlanTaskMap">
select * from plan, task where plan.id = task.pid and plan.id = #{id}
</select>
PlanMapper.java代碼
Plan select(int id);
note:pid是Task表的外鍵,這里面用的是collection標(biāo)簽
- select * from plan, task where plan.id = task.pid and plan.id = #{id} 一對多關(guān)聯(lián)查詢(方式二)
定義一個resultMap
<resultMap id="PlanTaskMap" type="com.baidu.pojo.entity.Plan">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<collection column="pid" property="tasks" ofType="com.baidu.pojo.entity.Task" select="getTask">
</collection>
</resultMap>
PlanMapper.xml代碼
<select id="select" parameterType="int" resultMap="PlanTaskMap">
select * from plan where id = #{id}
</select>
<select id="getTask" parameterType="int" resultType="com.baidu.pojo.entity.Task">
select * from task where id = #{id}
</select>
PlanMapper.java代碼
Plan select(int id);
note:先查詢出一條Plan記錄,然后把該記錄的id值作為Task表的pid,查詢對應(yīng)的多條Task記錄
補充
我們發(fā)現(xiàn),無論結(jié)果是返回一個值還是一個數(shù)組,resultType的返回類型都是單一的對象,但是Mapper.java里面有的是單一值,有的是list,MyBatis是如何知道我們想要的是一個結(jié)果還是多個結(jié)果。其實,無論返回一個還是多個,MyBatis都是按照多個結(jié)果查詢,看一下selectOne源碼:
public <T> T selectOne(String statement, Object parameter) {
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;
}
}
即使使用的是selectOne方法,里面調(diào)用的還是selectList方法,然后返回第一個值,代碼中有一句大家可能會很熟悉。當(dāng)返回值有多個,但是接口中的返回類型是單一的對象的時候,就會拋該錯誤