一、多对一处理
- 多个学生,对应一个老师
- 对于学生这边而言,关联,多个学生关联一个老师【多对一】
- 对于老师而言,集合,一个老师,有很多学生【一对多】
SQL:
CREATE TABLE teacher(
id INT(10) NOT NULL,
name VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (id)
)ENGINE=INNODB;
INSERT INTO teacher (id, name) VALUES (1, '果冻奶酪');
CREATE TABLE student(
id INT(10) NOT NULL,
name VARCHAR(30) DEFAULT NULL,
tid INT(10) DEFAULT NULL,
PRIMARY KEY(id),
KEY fktid (tid),
CONSTRAINT fktid FOREIGN KEY (tid) REFERENCES teacher (id)
)ENGINE=INNODB;
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);
测试环境搭建——这里运营了lombok
1、导入lombok
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
2、新建实体类Teacher、Student
@Data
public class Teacher {
private int id;
private String name;
}
@Data
public class Student {
private int id;
private String name;
//学生需要关联一个老师
private Teacher teacher;
}
3、建立Mapper接口
public interface TeacherMapper {
@Select("select * from teacher where id = #{id}")
Teacher getTeacher(@Param("id") int id);
}
public interface StudentMapper {
}
4、建立Mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 绑定Mapper接口 -->
<mapper namespace="com.oykq.dao.StudentMapper">
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 绑定Mapper接口 -->
<mapper namespace="com.oykq.dao.TeacherMapper">
</mapper>
5、核心配置文件中绑定注册Mapper接口或者文件
<mappers>
<mapper class="com.oykq.dao.TeacherMapper"/>
<mapper class="com.oykq.dao.StudentMapper"/>
</mappers>
6、测试查询是否成功
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
sqlSession.close();
}
按照查询嵌套处理
<!--
思路;
1.查询所有的学生信息
2.根据查询出来的学生的tid,寻找对应的老师 子查询
-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student;
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!-- 复杂的属性,需要单独处理
对象:association
集合:collection
-->
<!--
javaType:把SQL语句查询出来的结果集,封装给某个类的对象(可省略)
select:下一条要执行的SQL语句
property:注入给实体类的某个属性
上一次的查询结果集中,用哪些值作为条件去执行下一条SQL语句
-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id};
</select>
按照结果嵌套处理
<!-- 按照结果嵌套查询 -->
<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="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
MySQL多对一查询方式:
- 子查询
- 联表查询
二、一对多处理
比如一个老师有多个学生
对于老师而言,就是一对多的关系
环境搭建
1、环境搭建
实体类
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
//一个老师拥有多个学生
private List<Student> students;
}
按照结果嵌套处理
<!-- 按照结果嵌套查询 -->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname, t.name tname,t.id tid
from teacher t, student s
where t.id = s.tid and t.id = #{tid};
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- 复杂的属性,需要单独处理 对象:association 集合:collection
javaType="" 指定类型的属性
集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
按照查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id = #{tid};
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<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>
小结
1、关联 - association【多对一】
2、集合 - collection【一对多】
3、javaType & ofType
- javaType用来指定实体类中属性的类型
- ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束条件
注意点:
- 保证SQL的可读性,尽量保证通俗易懂
- 注意一对多和多对一中,属性名和字段的对应问题
- 如果问题不好排查错误,可以使用日志,建议用Log4j
慢SQL:
面试必问:
- Mysql引擎
- InnoDB底层原理
- 索引
- 索引优化
三、动态SQL
什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句
利用动态 SQL,可以彻底摆脱这种痛苦。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
搭建环境
CREATE TABLE blog(
id varchar(50) NOT NULL COMMENT '博客id',
title varchar(100) NOT NULL COMMENT '博客标题',
author varchar(30) NOT NULL COMMENT '博客作者',
create_time datetime NOT NULL COMMENT '创建时间',
views int(30) NOT NULL COMMENT '浏览量'
)ENGINE=InnoDB;
创建一个基础工程
- 导包
- 编写配置文件
- 编写实体类
- 编写对应实体类的Mapper接口
- 编写对应Mapper.xml文件
- 测试
IF
<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>
choose (when, otherwise)
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
if
where , choose , set , when
SQL片段
有时候,我们可能会将一些公共的部分抽取出来,方便复用
1、用sql标签抽取公共的部分
<sql id="if_title_author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
2、在需要的地方用include标签引用
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<include refid="if_title_author"></include>
</where>
</select>
注意事项:
- 最好基于单表定义SQL片段
- 不要存在where标签
Foreach
select * from user where 1=1 and
<foreach item="id" collection="ids"
open="(" separator="or" close=")">
#{id}
</foreach>
(id = 1 or id = 2 or id = 3)
<!--
select * from blog where 1=1 and (id=1 or id=2 or id=3)
我们传递一个Map,在Map中可以存在一个集合
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<foreach item="id" collection="ids" open="(" separator="or" close=")">
id = #{id}
</foreach>
</where>
</select>
动态SQL就是拼接SQL语句,我们只要保证SQL语句的正确性,按照SQL的格式,去排列组合就可以了
建议:
- 先在Mysql中写出完整的SQL语句,再对应地去修改成为动态SQL实现通用