一、resultMap用法
1.1、使用场景
- 字段名称和程序中的属性名不同的情况,可使⽤ resultMap 配置映射;
- ⼀对⼀和⼀对多关系可以使⽤ resultMap 映射并查询数据(在多表查询中,resultMap 不是企业中最常用的,后面讲多表查询的时候会讲一种最常用的方法)。
Ps拓展:
当程序中的属性名和表中的字段名不一致时的解决方案有两种:
1、使用 resultMap 标签(本篇重点讲解)。
2、使用数据库中的别名 as 重命名。
1.2、用法说明
1.2.1、模拟场景
例如,我们的表是这样定义的,如下:
但是程序中定义的熟悉如下(username字段 变成了 name属性):
这时候如果通过id来查询用户的全部数据,那么得到的 userinfo 对象的 name 属性值就为空,也就是说,当表中的字段名和属性名不一致时,查询到该属性的值就是空。
1.2.2、使用
这时候可以使用 resultMap来映射不一样的字段名就可以解决上述问题,如下:
<resultMap id="baseMap" type="com.example.demo.entity.Userinfo">
<id column="id" property="id"></id>
<result column="username" property="name"></result>
<result column="password" property="password"></result>
<result column="photo" property="photo"></result>
<result column="createtime" property="createtime"></result>
<result column="updatetime" property="updatetime"></result>
<result column="state" property="state"></result>
</resultMap>
<select id="getUserById" resultMap="baseMap">
select * from userinfo where id = ${id}
</select>
解释:
二、多表联查
2.1、分析
也许你听到过使用 association 进行多表联查,但是有些情况下显得过于繁琐,所以对于多表查询最终的一个解决方案:联合查询语句(left join / right join...) + XXXVO 来解决(这里的XXX 表示类名,VO 是 ViewObject 的缩写,这个类表示:是在一个实体类的基础上多加了一些属性值而新创建的一个类)。
例如:现在有一个文章表(articleinfo),和一个用户表(userinfo)如下,需要通过查询用户的 id 来查询该用户的所有文章,我们需要保留的字段为 文章表的所有信息 和 用户表的用户名,那么我们的 sql 可以这样写,如下(例如查询 id = 1):
select a.*, u.username from articleinfo a
left join userinfo u
on a.uid = u.id
where u.id = 1;
2.2、方法一:直接copy父类属性
具体的,我们按照如下步骤进行联合查询:
a)创建一个 XXXVO 类,它的基础实体类为 文章表 ,通过上面的 sql 查询可以知道,还需要增加 用户表的用户名属性,如下代码:
@Data
public class ArticleinfoVO extends Articleinfo implements Serializable {
private final long serializable = 1L;//用来保证兼容序列化和反序列化版本;
//新增的属性(用户表的用户名)
private String username;
//以前创建的基础表具有的属性
private int id;
private String title;
private String content;
private String createtime;
private String updatetime;
private int uid;
private int rcount;
private int state;
}
Ps:
1.继承 Serializable 接口是为了防止序列化和反序列化会出问题(建议实体类都写上!防止某些特定场景报错(例如使用Redis缓存就一定会报错));
2.private final long serializable = 1L; 用来保证兼容序列化和反序列化版本,当有新版本出现时,直接修改值即可。
b)设计接口,传入 id 即可,如下代码:
import com.example.demo.entity.vo.ArticleinfoVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface ArticleMapper {
ArticleinfoVO getAllVOById(@Param("id") Integer id);
}
Ps:注意返回类型是 XXXVO 类
c)在 XXXMapper.xml 文件中,实现对应 sql 即可,如下代码:
<select id="getAllVOById" resultType="com.example.demo.entity.vo.ArticleinfoVO">
select a.*, u.username from articleinfo a
left join userinfo u on a.uid = u.id
where a.id = #{id}
</select>
2.3、方法二:继承父类属性
和方法一的步骤一样,唯一需要我们进行修改的就是 XXXVO 类这里我们使用一个继承的方式,如下:
import com.example.demo.entity.Articleinfo;
import lombok.Data;
@Data
public class ArticleinfoVO extends Articleinfo implements Serializable {
private final long serializable = 1L;//用来保证兼容序列化和反序列化版本;
//新增的属性(用户表的用户名)
private String username;
//这里由于 lombok 的原因( lombok 的 toString 方法不会描述父类的属性),
@Override
public String toString() {
return "ArticleinfoVO{" +
"username='" + username + '\'' +
"} " + super.toString();
}
}
值得注意的是:我们需要重写 toString 方法,因为 lombok 的 toString 方法不会描述父类的属性!
2.4、总结
这样就可以实现一个更简单的联合查询啦~ 这种方式具有更高的灵活性,如果联合查询结果需要更多的属性时,那么只需要重新创建一个类,赋值旧的实体类,增加新的属性值即可~