ResultMat的使用
# ResultMat的使用🌊
resultMap
元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBCResultSets
数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。- 实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份
resultMap
能够代替实现同等功能的数千行代码。 - ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
# 1、简单结果集映射
解决属性名和字段名不一致的问题
【示例】数据库中的User
表字段
- userid
- username
- userphone
- userpassword
- jurisdiction
- createtime
- logintime
- userstatus
数据库中的字段和实体类中的字段不一致。
【示例】User.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String phone;
private String password;
private int juri;
private String created;
private String logined;
private int status;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
使用结果集映射
【示例】UserMapper.xml
<mapper namespace="com.singerw.mapper.UserMapper">
<!--查询所有用户-->
<select id="getUsers" resultMap="userMap">
select *
from goku.g_users
</select>
<!--根据ID查询用户-->
<select id="getUser" resultMap="userMap">
select *
from goku.g_users
where userid = #{userid}
</select>
<!--resultMap结果集映射-->
<resultMap id="userMap" type="User">
<!-- 实体类和表列做关联-->
<!-- id 主键 属性 -->
<id property="id" column="userid"></id>
<!--其他部分-->
<!--column数据库中的字段,property实体类中的属性-->
<result property="name" column="username"></result>
<result property="phone" column="userphone"></result>
<result property="password" column="userpassword"></result>
<result property="jurisdiction" column="jurisdiction"></result>
<result property="juri" column="createtime"></result>
<result property="created" column="createtime"></result>
<result property="logined" column="logintime"></result>
<result property="status" column="userstatus"></result>
</resultMap>
</mapper>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
【示例】UserMapperTest.java
public class UserMapperTest {
private SqlSession sqlSession = MyBatisUtils.getSqlSession();
private UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
@Test
public void getUsers() {
List<User> users = userMapper.getUsers();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
@Test
public void getUser() {
User user = userMapper.getUser(2);
System.out.println(user);
sqlSession.close();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 2、Association完整案例
一个复杂类型的关联,按照结果嵌套查询,多对一。
🌊(以1:N为案例关联映射)🌊
在数据库设计中,普遍存在一对多,多对一的表关系。blogdb数据库中三个基本表结构如下 。
在数据库表设计的过程中,建立了如上的表结构,那么到程序设计中,实体类应该怎么写呢?
一个作者可以发表多篇文章,而发表的这些多篇文章只能有一个作者,这里文章和作者是1:N的关系。
Article(N)
:如果需要得到一篇或多篇文章的作者,需要在实体类中增加一个类型。
private Users users
User(1)
:在user表中查询某一用户的时候,同时想得到这个用户发表了哪些文章,需要在实体类中增加一个集合。
private List<Article> articleList
通过关键字或者文章ID查询一篇或多篇文章和每篇文章的作者信息
# 步骤一、编写实体类
【实体类示例】:Article.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Article {
private int id;
private String title;
private String content;
private String summary;
private int cid;
private Users users;
private String created;
private int status;
}
2
3
4
5
6
7
8
9
10
11
12
13
【实体类示例】:Users.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
private int id;
private String username;
private String nickname;
private String password;
private int status;
private String email;
private String userface;
private String created;
private String lastlogin;
private List<Article> articleList;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 步骤二、实现数据查询操作
【SQL语句示例】
<!--使用了resultMap,需要在xml中创建一个id为articleMap的resultMap-->
<select id="getArticles" resultMap="articleMap">
SELECT article.id,
article.title,
article.content,
article.summary,
article.created,
article.`status`,
`user`.id AS uid,
`user`.username,
`user`.nickname
FROM article
INNER JOIN `user` ON article.uid = `user`.id
WHERE article.title LIKE #{title}
</select>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 步骤三、编写查询方法接口
【查询方法示例】:ArticleMapper.java
public interface ArticleMapper {
List<Article> getArticles(String title);
}
2
3
4
# 步骤四、编写mapper.xml中的ResultMap
【ResultMap关联示例】:ArticleMapper.xml
<!-- 映射关系的管理和定义 ,type指的是实体类型(取了别名),id当前的resultMap的名字 -->
<resultMap type="Article" id="articleMap">
<!-- 主键使用id -->
<id property="id" column="id"/>
<!-- 一个result表示一个列和实体类的属性的对应关系 -->
<result property="title" column="title"/>
<result property="content" column="content"/>
<result property="summary" column="summary"/>
<result property="created" column="created"/>
<result property="status" column="status"/>
<!-- 此时我们的Article类中,增加了一个Users类型的属性 -->
<association property="users" column="uid" javaType="com.singerw.pojo.Users">
<!-- author类对应的表中的列 和 类属性关联 -->
<id property="id" column="uid"/>
<result property="username" column="username"/>
<result property="nickname" column="nickname"/>
</association>
</resultMap>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 步骤五、进行单元测试
public class ArticleMapperTest {
@Test
public void getArticles() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
ArticleMapper mapper = sqlSession.getMapper(ArticleMapper.class);
List<Article> articles = mapper.getArticles("%VUE%");
articles.forEach(System.out::println);
}
}
2
3
4
5
6
7
8
9
10
Article(id=2, title=VUE, content=VUE是极简的前端框架, summary=vue, category=null, users=Users(id=1, username=tom, nickname=唐木松, password=null, status=0, email=null, userface=null, created=null, lastlogin=null, articleList=null, categoriesList=null), created=2020-12-25 01:20:20, status=1)
# 3、Collection节点案例
一个复杂类型的集合。按照结果嵌套查询,一对多。
🌊(以1:N为案例关联映射)🌊
在数据库设计中,普遍存在一对多,多对一的表关系。blogdb数据库中三个基本表结构如下 。
在数据库表设计的过程中,建立了如上的表结构,那么到程序设计中,实体类应该怎么写呢?
一个作者可以发表多篇文章,而发表的这些多篇文章只能有一个作者,这里文章和作者是1:N的关系。
Article(N)
:如果需要得到一篇或多篇文章的作者,需要在实体类中增加一个类型。
private Users users
User(1)
:在user表中查询某一用户的时候,同时想得到这个用户发表了哪些文章,需要在实体类中增加一个集合。
private List<Article> articleList
通过用户ID查询用户和用户发表的文章
# 步骤一、编写实体类
【实体类示例】:Article.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Article {
private int id;
private String title;
private String content;
private String summary;
private int cid;
private Users users;
private String created;
private int status;
}
2
3
4
5
6
7
8
9
10
11
12
13
【实体类示例】:Users.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
private int id;
private String username;
private String nickname;
private String password;
private int status;
private String email;
private String userface;
private String created;
private String lastlogin;
private List<Article> articleList;
private List<Category> categoriesList;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 步骤二、实现数据查询操作
【SQL语句示例】
SELECT `user`.id AS userid,
`user`.username,
`user`.nickname,
`user`.`password`,
`user`.`status` AS userstatus,
`user`.email,
`user`.userface,
`user`.created AS user_created,
`user`.lastlogin,
article.id AS articleid,
article.title,
article.content,
article.summary,
article.created,
article.STATUS AS articlestatus
FROM `user`
INNER JOIN article ON `user`.id = article.uid
WHERE `user`.id = #{id}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 步骤三、编写查询方法接口
【查询方法示例】:UsersMapper.java
public interface UsersMapper {
<List>Users getUserAndArticle(int id);
}
2
3
4
# 步骤四、编写mapper.xml中的ResultMap
【ResultMap关联示例】:UsersMapper.xml
<!-- 映射关系的管理和定义 ,type指的是实体类型,id当前的resultMap的名字 -->
<resultMap type="Users" id="userMap2">
<!-- 主键使用id -->
<id property="id" column="userid"/>
<!-- 一个result表示一个列和实体类的属性的对应关系 -->
<result property="username" column="username"/>
<result property="nickname" column="nickname"/>
<result property="password" column="password"/>
<result property="status" column="userstatus"/>
<result property="email" column="email"/>
<result property="userface" column="userface"/>
<result property="created" column="user_created"/>
<result property="lastlogin" column="lastlogin"/>
<collection property="articleList" ofType="Article">
<id property="id" column="articleid"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<result property="summary" column="summary"/>
<result property="created" column="category_created"/>
<result property="status" column="articlestatus"/>
</collection>
</resultMap>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 步骤五、进行单元测试
public class UsersMapperTest {
@Test
public void getUserAndArticle() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
Users user = mapper.getUserAndArticle(2);
System.out.println(user);
}
}
2
3
4
5
6
7
8
9
10
Users(id=2, username=jerry, nickname=吴八阁, password=e10adc3949ba59abbe56e057f20f883e, status=1, email=jerry@qq.com, userface=jerry.jpg, created=2021-01-08 01:01:22, lastlogin=2020-12-08 01:01:22, articleList=[Article(id=1, title=SpringBoot, content=SpringBoot是spring全家桶中很重要的一员, summary=spring, category=null, users=null, created=null, status=1), Article(id=5, title=MySQL, content=VUE是极简的前端框架, summary=vue, category=null, users=null, created=null, status=1), Article(id=7, title=Dubbo, content=VUE是极简的前端框架, summary=vue, category=null, users=null, created=null, status=1), Article(id=8, title=RabbitMQ, content=VUE是极简的前端框架, summary=vue, category=null, users=null, created=null, status=1), Article(id=10, title=Oracle, content=VUE是极简的前端框架, summary=vue, category=null, users=null, created=null, status=1), Article(id=12, title=Layui, content=VUE是极简的前端框架, summary=vue, category=null, users=null, created=null, status=1)], categoriesList=null)
# 4、ResultMap使用常见问题
1、使用别名时,要创建别名
<resultMap type="Users" id="userMap2">
<!-- 别名 -->
<typeAliases>
<typeAlias type="com.singerw.pojo.Users" alias="Users" />
</typeAliases>
2
3
4
2、使用resultMap
时需要先创建一个resultMap
<select id="getCategoryAndArticle" resultMap="categoryMap">
...
</select>
2
3
<resultMap id="categoryMap" type="Category">
...
</resultMap>
2
3
3、resultMap
中的每张表都要求都有主键
<id property="id" column="id"/>
<resultMap id="categoryMap" type="Category">
<!--主键-->
<id property="id" column="id"/>
<!--其他部分-->
<result property="catename" column="catename"/>
...
<collection property="articleList" ofType="Article">
<result property="id" column="art_id"/>
...
</collection>
</resultMap>
2
3
4
5
6
7
8
9
10
11
4、result
中property
需要实体类中的属性名,column
是表中的类名。
<result property="id" column="art_id"/>
5、JavaType
:是用来指定实体类中属性的类型。
6、ofType
:是用来指定映射到List或者集合中的实体类类型,泛型中的约束类型!