Mybatis学习(三) resultMap(结果映射) 和动态Sql
1.resultMap
1.1、resultMap简单概述
- resultMap 元素是 MyBatis 中最重要最强大的元素。
- ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了
- ResultMap 最优秀的地方在于,虽然你已经对它相当了解了,但是根本就不需要显式地用到他们。
简单案例
<!--结果集映射-->
<resultMap id="UserMap" type="User">
<!--column数据库中的字段,property实体类中的属性-->
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
<select id="getUserById" resultMap="UserMap">
select * from mybatis.user where id = #{id}
</select>
1.1.1、resultMap 的属性列表
属性 | 描述 |
---|---|
id | 当前命名空间中的一个唯一标识,用于标识一个结果映射。 |
type | 类的完全限定名, 或者一个类型别名(关于内置的类型别名,可以参考上面的表格)。 |
autoMapping | 如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。 |
1.1.2、resultMap 常用元素
- id : 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
- result : 注入到字段或 JavaBean 属性的普通结果
- association : 一个复杂类型的关联;许多结果将包装成这种类型
- 嵌套结果映射 – 关联可以是 resultMap元素,或是对其它结果映射的引用
- collection : 一个复杂类型的集合
- 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
1.1.3、Id 和 Result 的属性
属性 | 描述 |
---|---|
property | 映射到列结果的字段或属性。 |
column | 数据库中的列名,或者是列的别名。 |
javaType | 一个 Java 类的全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 |
jdbcType | JDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。 |
typeHandler | 默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。这个属性值是一个类型处理器实现类的全限定名,或者是类型别名。 |
id 和 result元素的相同点是都将一个列的值映射到一个简单数据类型的属性或字段。
不同点是 id 元素对应的属性会被标记为对象的标识符,在比较对象实例时使用。可提高整体的性能。
2.2、resultMap的关联操作案例
SQL
CREATE TABLE `teacher` (
`id` INT(10) PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(40) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO teacher(`id`, `name`) VALUES (1, '李老师');
CREATE TABLE `student` (
`id` INT(10) PRIMARY KEY Auto_Increment,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '张三', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '李四', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '王五', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '赵六', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '孙七', '1');
建立一个学生信息表和一个老师信息表 多个学生对应一个老师
编写学生和老师的pojo实体类
public class Student {
private int id;
private String name;
private Teacher teacher;//每个学生都有一名老师教他
public Student() {
}
public Student(int id, String name, Teacher teacher) {
this.id = id;
this.name = name;
this.teacher = teacher;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", teacher=" + teacher +
'}';
}
}
public class Teacher {
private int id;
private String name;
public Teacher() {
}
public Teacher(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
查询嵌套处理
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.song.mapper.StudentMapper">
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="com.song.pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="com.song.pojo.Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="com.song.pojo.Teacher">
select * from teacher where id = #{id}
</select>
</mapper>
测试
@Test
public void TestStudent(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent();
for (Student student : studentList) {
System.out.println(student);
}
sqlSession.close();
}
结果嵌套处理
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid = t.id;
</select>
<resultMap id="StudentTeacher2" type="com.song.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="com.song.pojo.Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
跟上面测试一样 根据自己的习惯选择用那种方式
2.3、reslutMap的集合操作案例
还是跟上面一样的表
pojo实体类稍作修改 (省略了set get 构造 toString方法 自己补充 )
public class Student {
private int id;
private String name;
private int tid;
}
public class Teacher {
private int id;
private String name;
//一个老师拥有多个学生
private List<Student> students;
}
查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from mybatis.student where tid = #{tid}
</select>
结果嵌套处理
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname, t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="com.song.pojo.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="com.song.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
JavaType 用来指定实体类中属性的类型
ofType 用来指定映射到List或者集合中的 pojo类型,泛型中的约束类型!
2.4、使用reslutMap来进行分页效果
//进行分页操作 万能的map
public List<User> getUserByLimit(Map<String,Integer> map);
<!--分页-->
<select id="getUserByLimit" resultType="User" parameterType="map">
select * from jdbc.users limit #{startIndex},#{pageSize}
</select>
@Test
public void test1(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> ListMap = new HashMap<String, Integer>();
ListMap.put("startIndex",1);
ListMap.put("pageSize",2);
List<User> userByLimit = mapper.getUserByLimit(ListMap);
for (User user : userByLimit) {
System.out.println(user);
}
}
2.动态Sql
2.1、什么是动态sql 为什么要使用它
- 动态 SQL 是 MyBatis 的强大特性之一
- 根据不同的条件去刷选sql语句 相当于动态的去判断(我去查询姓名还是年龄 还是其他一些操作)
- 实质上还是sql语句 通过一些条件去拼接sql
基于 OGNL 的表达式
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
2.2、IF
如果传入的title不为空 则进行拼接 and title = #{title} 下面的也一样 进行判断
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
2.3、choose、when、otherwise
choose 元素,它有点像 Java 中的 switch 语句
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
2.4、trim、where、set
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
会移除所有 prefixOverrides 属性中指定的内容 会插入 prefix 属性中指定的内容。
<trim prefix="SET" suffixOverrides=",">
...
</trim>
覆盖了后缀值设置,并且自定义了前缀值
2.5、foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
若想更好的了解Mybatis建议自己阅读 Mybatis官方文档
推荐学习Mybatis的视频 B站 狂神说java 或者 尚硅谷雷丰阳老师
谢谢大家的阅读! 若上面有写错的 欢迎纠正哦!