# MyBatis教程 - 6 查询结果
下面介绍一下 MyBatis 中查询结果的处理。
查询结果可能是一条记录、多条记录、数据库中的字段和 Java 实体类中的属性值不对应等情况,下面进行介绍。
# 6.1 查询结果为单条记录
如果查询结果为单条记录,那么可以直接使用实体类对象进行接收。前面也多次用到,再介绍一下。
在通过用户名
查询用户的时候,可以编写接口如下:
UserMapper.java
:
/**
* 根据用户名查询用户
*/
User selectByUsername(@Param("username") String username);
2
3
4
在 UserMapper.xml 中通过 resultType
映射返回结果的类型(这里使用了别名,前面讲过),如下:
<select id="selectByUsername" resultType="User">
SELECT * FROM tb_user
WHERE username = #{username}
</select>
2
3
4
# 6.2 查询结果为多条记录
当查询返回多条记录时,MyBatis 会将每一条记录映射为一个 Java 对象,并将这些对象放入一个 List
中。
举个栗子:
查询所有的用户,可以编写接口如下:
UserMapper.java
:
/**
* 查询所有用户
*/
List<User> selectAll();
2
3
4
接口需要使用 List 来接收。当然返回的单条记录,接口返回类型也可以定义为 List。
在 UserMapper.xml 中和查询单条是一样的,也是通过 resultType
映射返回结果的类型,如下:
<select id="selectAll" resultType="User">
SELECT * FROM tb_user
</select>
2
3
# 6.3 查询单列数据
当使用聚合函数,例如使用 count 函数来查询数据库中记录数的时候,返回的是一列数据,那么此时如何接收数据呢?
举个栗子:
查询用户个数,可以编写接口如下:
UserMapper.java
:
/**
* 查询所有用户数量
*/
Integer selectAllCount();
2
3
4
返回的数据类型是整形的,是条目的数量。
在 UserMapper.xml 中,编写 SQL ,使用 count 查询记录数:
<select id="selectAllCount" resultType="java.lang.Integer">
SELECT COUNT(*) FROM tb_user
</select>
2
3
返回的结果类型为 java.lang.Integer
,MyBatis 是内置了类型别名,所以这里的 java.lang.Integer
可以写为:Integer
、integer
、int
、Int
都可以。
再举个栗子:
下面查询所有的用户名,单列,但是是一个 username 的 List<String>
。
编写接口如下:
UserMapper.java
:
/**
* 查询所有用户的用户名
*/
List<String> selectAllUsername();
2
3
4
返回的是一个 username 的集合。
在 UserMapper.xml 中,查询所有的用户名:
<select id="selectAllUsername" resultType="String">
SELECT username FROM tb_user
</select>
2
3
# 6.4 返回Map类型
我们可以将查询的结果解析到一个 Map 中,但是注意,这种情况,只能处理返回结果是单条记录的情况。
举个栗子:
根据 ID 查询用户,编写接口如下。
UserMapper.java
:
/**
* 根据ID查询用户信息,并返回Map类型
*/
Map<String, Object> selectByIdToMap(@Param("id") Integer id);
2
3
4
返回的是 Map 类型。
在 UserMapper.xml 中,设置 resultType="Map"
,SQL 没有区别:
<select id="selectByIdToMap" resultType="Map">
SELECT * FROM tb_user
WHERE id = #{id}
</select>
2
3
4
查询到的数据格式是:
{
password=123456,
update_time=2024-08-17T08:03:52,
create_time=2024-08-17T08:03:52,
id=1,
email=doubi@foooor.com,
age=30,
username=doubi
}
2
3
4
5
6
7
8
9
key
为数据库中的字段,value
为对应的值。
如果查询出的结果,没有或不想使用实体类对应,可以使用 Map 来接收。
# 6.5 使用Map接收多条记录
上面使用 Map 接收返回的结果,只能接收单条查询记录,如果使用 Map 接收多条记录,需要返回一个 Map 的 List 集合。
举个栗子:
查询所有的用户信息,使用 List<Map>
接收。
UserMapper.java
:
/**
* 查询所有用户的信息,并返回Map类型
*/
List<Map<String, Object>> selectAllToMap();
2
3
4
在 UserMapper.xml 中,还是设置 resultType="Map"
,没有区别:
<select id="selectAllToMap" resultType="Map">
SELECT * FROM tb_user
</select>
2
3
这样每条记录对应 List 中的一个 Map 对象中的数据。
还有一种使用 Map 接收多条记录的方式,在接口上添加 @MapKey
注解:
/**
* 查询所有用户的信息,并返回Map类型
*/
@MapKey("id")
Map<String, Map<String, Object>> selectAllToMap();
2
3
4
5
上面的配置的意思,返回结果是一个 Map,Map 的 key 是每条记录的 id 字段的值,因为使用 @MapKey("id")
指定了。
value
是一个 Map,这个 Map 中是每条记录在数据库中对应的字段和属性值。
所以结果的格式如下:
{
1={
password=123456,
update_time=2024-08-17T08:03:52,
create_time=2024-08-17T08:03:52,
id=1,
email=doubi@foooor.com,
age=30,
username=doubi
},
2={
password=1234qwer,
update_time=2024-08-17T08:03:52,
create_time=2024-08-17T08:03:52,
id=2,
email=niubi@foooor.com,
age=28,
username=niubi},
3={
password=88888888,
update_time=2024-08-17T08:03:52,
create_time=2024-08-17T08:03:52,
id=3,
email=erbi@foooor.com,
age=35,
username=erbi
}
}
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
UserMapper.xml
中的配置和上面 List<Map>
接收的方式一样,没有变化。
# 6.6 字段与属性匹配
数据库中的字段一般使用的都是小写字母,多个单词使用下划线 _
来分割。而在 Java 中的属性一般都是使用小写字母开头的驼峰规则。
这样数据库的字段和 Java 实体类中的属性名称不完全对应,这样就会存在数据库查询的结果无法赋值给 Java 对象,导致对象属性值为 null。
针对这种情况有三种处理方式,下面介绍一下。
# 1 全局配置
在 HelloWorld 章节已经讲过了,通过在 mybatis-config.xml 中配置如下属性,可以让数据库中的字段使用驼峰命名法与 Java 实体类中的属性进行映射。
<!-- 设置 -->
<settings>
<!-- 驼峰命名法 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
2
3
4
5
这样数据库的 user_name
可以对应 Java 实体类中的 userName
。这个配置默认为 false
,所以需要显式配置为 true
。
# 2 SQL别名
但是有时候,数据库的字段与 Java 实体类中的字段名称没有那么对应,例如数据库字段叫 email
,Java 属性中叫 mailBox
(只是举个例子),这样即使配置了驼峰命名法也无法解决。
那么我们可以修改 SQL,使用字段别名来解决。
举个栗子:
<select id="selectById" resultType="User">
SELECT id, username, password, email as mailBox FROM tb_user
WHERE id = #{id}
</select>
2
3
4
在 SQL 中,通过给 email
设置别名 email as mailBox
(as
可以省略),和 Java 中的 mailBox
属性对应即可。
# 3 ResultMap
使用 ResultMap 可以将数据库的字段和 Java 实体类中的属性进行一一映射。
举个栗子:
首先需要在 XxxMapper.xml
中使用 <resultMap>
标签定义 ResultMap,然后在查询的时候,指定 resultMap
。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.foooor.mybatis.mapper.UserMapper">
<!--
1. id:指定resultMap的唯一标识符
2. type:指定对应的实体类型
2. <id> 表示的是主键
3. <result> 表示的是普通字段,property 表示的是实体类的属性;column 表示的是数据库的字段
-->
<!-- 定义resultMap结果集映射 -->
<resultMap id="UserResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="mailBox" column="email"/>
<result property="age" column="age"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<!-- 查询,使用resultMap -->
<select id="selectById" resultMap="UserResultMap">
SELECT * FROM tb_user
WHERE id = #{id}
</select>
<!-- ... 其他SQL映射 -->
</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
33
首先定义 ResultMap,然后在查询的时候通过 resultMap
属性来指定。
注意:在 ResultMap 中,如果字段名称匹配,可以不写;所以上面 username
、password
等选项可以省略的,只写 mailBox
。因为指定了类为 User
,会将名称匹配的字段和属性自动进行映射。
ResultMap
更多的使用方式是用来配置一对多、多对一的映射。后面再介绍。