官方说明文档: http://www.mybatis.org/mybatis-3/zh/index.html#
resultType 和 resultMap 区别
resultType: 从这条语句中返回的期望类型的类的完全限定名或别名. 注意如果是集合情形, 那应该是集合可以包含的类型, 而不能是集合本身. 使用 resultType 或 resultMap, 但不能同时使用.
也就是说, 使用 resultType 直接表示的就是返回类型, 可以是基本类型 (int,string),list,map 这些, 也可以是具体的 pojo 对象
完全限定名, 意思是例如返回 Task 对象, 那么值填写的是该 Task 类的完整类路径; 如果返回的是基础类型, 就是类似 java.util.Map
别名, 意思是例如返回 map 类型, 我们不需要写完整的 java.util.Map, 可以用 map 替代
不能是集合本身, 这句话意思是例如接口需要返回 List<Task>, 那么直接写 resultType="com.baidu.vo.Task", 而不是写成 resultType="List<com.baidu.vo.Task>"
resultMap: 外部 resultMap 的命名引用. 结果集的映射是 MyBatis 最强大的特性, 对其有一个很好的理解的话, 许多复杂映射的情形都能迎刃而解. 使用 resultMap 或 resultType, 但不能同时使用.
相对复杂一点, 需要先定义一个外部标签 < resultMap>, 这里面一般定义了结果到 pojo 的映射关系, 有 id 属性, 在具体的查询语句中通过 id 寻找对应的 resultMap
外部 resultMap 的命名引用, 意思是并不是直接的返回类型, 只是一个引用标识, 需要去找对应的该引用的定义地方
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: 通过上面两个例子发现, 无论输出单个对象还是一个列表, resultType 的类型都是一样的. 如果第二个例子中, TaskMapper.java 里面方法返回值类型是 Task 而不是 List<Task > 的话, 当查询的结果包含多条语句时, 就会抛 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 对象, 列名对应键, 结果对应值, 如果是多条结果, 那么应该映射为类型的 map 的一个集合
select status, count(*) as num from task group by status desc 统计任务表里所有状态的个数
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 的数组
select * from task where id in (3, 4, 5) 参数是一个数组
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 代表循环中的具体对象, 如果 collection 属性是 list, 那 item 就表示 list 中的一个元素; collection 是遍历的对象, 可以是 list,array, 如果 Mapper.java 里传入参数时使用 @param("param") 来设置名字, 那这里的 collection 属性就填写对应的参数名; separator 是分隔符, 例如 sql 中出现 in 语句时, 就会设置 separator="," 分隔; open 和 close 代表 in 语句里面的前后括号
insert into task (title, name) values ('标题', '名字') 参数是一个 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 注解, 对应的 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 代表数据库表里面的属性, property 代表赋值给实体对象的属性
定义一个 sql
<sql id="Base_Column_List">
id, title, name, create_at
</sql>
note: 这个元素是用来定义可以重复使用的 sql 代码语句的, 这里面把 Task 表的全部列名定义为了一个 sql, 是为了下面查询语句的重复使用
select * from task where create_at = '2017-07-07' 查询数据
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 子句. 而且, 若最后的内容是 AND 或 OR 开头的, where 元素也知道如何将他们去除. 这里面的 if 语句很直观, 就是代表如果传入的参数中, 该属性不为空, 那么就把该条件带上去
insert into task (title, name,create_at) values ('标题', '名字', '2017-07-07') 插入数据
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 设置的属性中, 这里就是 id 是自增长的主键, 值可以通过 getGenereatedKeys 方法获取然后复制到 task 对象的属性上面
update task set name = '名字' where id = {id} 更新数据
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 元素会动态前置 SET 关键字, 同时也会消除无关的逗号
delete from task where create_at = '2017-07-07' 删除数据
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} 利用索引传递多个参数
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} 指定参数, 索引从 0 开始
select * from task where title = {title} and name = {name} 利用 @param 注解传递多个参数
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 - 关联查询
描述: 一个计划有一个执行人, 一个人只能执行一个计划
定义一个 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} 一对一关联查询 (方式一)
定义一个 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 标签
select * from plan, user where plan.uid = user.id and plan.id = #{id} 一对一关联查询 (方式二)
定义一个 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, 查询对应的 User 记录
描述: 一个计划可以执行多个任务, 一个任务属于一个计划
定义一个 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} 一对多关联查询 (方式一)
定义一个 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="PlanUserMap">
select * from plan, task where plan.id = task.pid and plan.id = #{id}
</select>
PlanMapper.java 代码
Plan select(int id);
note:pid 是 Task 表的外键, 这里面用的是 collection 标签
select * from plan, task where plan.id = task.pid and plan.id = #{id} 一对多关联查询 (方式二)
定义一个 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 user where id = #{id}
- </select>
PlanMapper.java 代码
Plan select(int id);
note: 先查询出一条 Plan 记录, 然后把该记录的 id 值作为 Task 表的 pid, 查询对应的多条 Task 记录
补充
我们发现, 无论结果是返回一个值还是一个数组, resultType 的返回类型都是单一的对象, 但是 Mapper.java 里面有的是单一值, 有的是 list,MyBatis 是如何知道我们想要的是一个结果还是多个结果. 其实, 无论返回一个还是多个, MyBatis 都是按照多个结果查询, 看一下 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 方法, 里面调用的还是 selectList 方法, 然后返回第一个值, 代码中有一句大家可能会很熟悉. 当返回值有多个, 但是接口中的返回类型是单一的对象的时候, 就会抛该错误
来源: http://www.bubuko.com/infodetail-2593611.html