MyBatis 返回结果
自动映射
MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略大小写)。 这意味着如果发现了数据库中的 ID 列和Java类中的 id 属性,MyBatis 会将列 ID 的值赋给 id 属性。
通常数据库列使用大写字母组成的单词命名,单词间用下划线分隔;而 Java 属性一般遵循驼峰命名法约定。为了在这两种命名方式之间启用自动映射,需要将mapUnderscoreToCamelCase
设置为 true。
<settings>
<!--开启自动驼峰命名规则映射, 如果数据库字段为user_email, MyBatis会自动将其映射到Javabean中的userEmail属性-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
resultType
通过resultType设置返回结果类型,基本数据类型与POJO类似,下面只演示POJO。
返回单个或者多个
- 通过
username
查询单个用户
接口定义如下
public User getUserByUserName(String userName);
接口对应的 Mapper.xml 定义如下所示
<select id="getUserByUserName"
parameterType="String"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
where username = #{username}
</select>
- 通过
username
查询多个用户
接口定义如下
public List<User> getUserListByUserName(String userName);
接口对应的 Mapper.xml 定义如下所示
<select id="getUserListByUserName"
parameterType="String"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
where username = #{username}
</select>
有时候需要将返回的List封装在一个Map里面,并使用实体类的某个字段作为Map的key
接口定义如下
@MapKey("id")
public Map<String, User> getUserListByUserName(String userName);
接口对应的 Mapper.xml 定义如下所示
<select id="getUserListByUserName"
parameterType="String"
resultType="map">
select
id, username, user_email userEmail, user_city userCity, age
from user
where username = #{username}
</select>
resultMap
有时候通过驼峰命名规则并不能映射到我们想要的JavaBean属性,就可以使用resultMap来实现高级结果集映射。
比如有一张user表里面有id、user_email、user_city这三个字段,有一个userVO
实体类有如下几个属性
public class UserVO {
private Integer id;
private String email;
private String city;
// 省略get、set方法
}
现在需要使用MyBatis将user信息查询出来并映射到userVO
实体类
接口定义如下
public UserVO getUserInfoById(Integer id);
接口对应的 Mapper.xml 定义如下所示
<resultMap id="userVO" type="com.example.mybatis.entity.UserVO">
<!--
指定主键类的封装规则
id定义主键,底层会有一些优化
column指定数据路的列
property指定对应的JavaBean属性
-->
<id column="id" property="id" />
<!--定义普通列的封装-->
<result column="user_email" property="email" />
<result column="user_city" property="city" />
</resultMap>
<select id="getUserInfoById" resultMap="userVO">
select * from user where id = #{id}
</select>
多表关联查询
实际开发中不可能只是对单表进行操作,一定会涉及到多表关联查询,数据表之间的关系有三种:一对一关系、一对多关系、多对多关系。
一对一
一个学生对应一个班级,而一个班级可以对应多个学生。
CREATE TABLE `t_classes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `t_student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(11) DEFAULT NULL,
`cid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `cid` (`cid`),
CONSTRAINT `student_ibfk` FOREIGN KEY (`cid`) REFERENCES `t_classes` (`id`)
);
实体类
public class Classes {
private Integer id;
private String name;
private List<Student> students;
}
public class Student {
private Integer id;
private String name;
private Classes classes;
}
通过学生id查询学生信息,并且把学生班级信息一起查询出来。
接口定义如下
public Student getStudentById(Integer id);
接口对应的 Mapper.xml 定义如下所示
<resultMap id="studentResultMap" type="Student">
<id column="sid" property="id" />
<result column="sname" property="name" />
<!-- 映射 classes 属性 -->
<association property="classes" javaType="com.example.mybatis.entity.Classes">
<id column="cid" property="id" />
<result column="cname" property="name" />
</association>
</resultMap>
<select id="getStudentById" resultMap="studentResultMap">
select s.id sid,s.name sname, c.id cid, c.name cname
from t_student s , t_classes c
where s.cid = c.id
and s.id = #{id}
</select>
将上面的查询语句修改为分步查询、延迟查询
<resultMap id="studentResultMap" type="com.example.mybatis.entity.Student">
<id column="id" property="id" />
<result column="name" property="name" />
<!--
映射 classes 属性
property: 映射到JavaBean中的属性
column: 指定某个列的值传递到 select 中的方法
select: 表名当前属性是调用select指定的方法查出的结果
如果是调用当前mapper中的方法, 则直接填写要调用方法的id就行了
如果是调用其它mapper中的方法, 则需要这样填写com.xxx.mapper.XxxMapper.getClassesById
fetchType: lazy-> 懒加载、eager-> 全部加载,
如果设置了懒加载模式, 那么当获取classes属性时才会从数据库中加载classes数据出来
javaType: 映射实体类
-->
<association property="classes"
column="cid"
select="getClassesById"
javaType="com.example.mybatis.entity.Classes"
fetchType="lazy">
<id column="id" property="id" />
<result column="name" property="name" />
</association>
</resultMap>
<select id="getStudentById" resultMap="studentResultMap">
select s.id,s.name,s.cid
from t_student s
where s.id = #{id}
</select>
<select id="getClassesById" resultType="com.example.mybatis.entity.Classes">
select c.id,c.name from t_classes c where c.id = #{id}
</select>
一对多
现在反过来查询 Classes,将级联的所有 Student 一并查询。
接口定义如下
public Classes getClassesById(Integer id);
接口对应的 Mapper.xml 定义如下所示
<resultMap id="classesResultMap" type="com.example.mybatis.entity.Classes">
<id column="cid" property="id" />
<result column="cname" property="name" />
<collection property="students" ofType="com.example.mybatis.entity.Student">
<id column="sid" property="id" />
<result column="sname" property="name"/>
</collection>
</resultMap>
<select id="getClassesById" resultMap="classesResultMap">
select s.id sid,s.name sname, c.id cid, c.name cname
from t_student s , t_classes c
where s.cid = c.id
and c.id = #{id}
</select>
需要注意的是 association 标签,通过设置 javaType 属性,映射实体类,collection 标签,通过设置 ofType 属性映射实体类。
将上面查询修改成分步查询、延迟查询
<resultMap id="classesResultMap" type="com.example.mybatis.entity.Classes">
<id column="cid" property="id" />
<result column="cname" property="name" />
<!--
这里的column只传递了一个字段,如果想传入多个字段可以这样写
column="{key1=column1, key2=column2}"
相当于封装成了一个Map, 当前查询可以这样写column="{id=cid}"
-->
<collection
fetchType="lazy"
property="students"
select="getStudentByClassesId"
column="cid">
</collection>
</resultMap>
<select id="getClassesById" resultMap="classesResultMap">
select c.id cid, c.name cname
from t_classes c
where c.id = #{id}
</select>
<select id="getStudentByClassesId" resultType="com.example.mybatis.entity.Student">
select s.id , s.name from t_student s where s.cid = #{id}
</select>
多对多
多对多其实是双向的一对多关系,所以双方都是用 collection 标签设置级联,与上面的一对多是类似的。
本作品采用《CC 协议》,转载必须注明作者和本文链接