多对一处理
多对一:
-
多个学生,对应一个老师
-
对于学生而言, 关联 ,多个学生,关联一个老师【多对一】
-
对于老师而言, 集合 ,一个老师有很多学生【一对多】
SQL
CREATE TABLE `teacher`
(
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = INNODB
DEFAULT CHARSET = utf8;
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
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');
测试环境搭建
-
导入lombok
-
新建实体类Teacher,Student
-
建立Mapper接口
-
建立Mapper.xml文件
-
在核心配置文件中绑定注册我们的Mapper接口或者文件【方式很多,自选】
-
测试查询是否能够成功!
// 学生实体类
@Data
public class Student {
private int id;
private String name;
private Teacher teacher;
}
// 老师实体类
@Data
public class Teacher {
private int id;
private String 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.lwh.dao.StudentMapper">
<!--
思路:
1. 查询所有的学生信息
2. 根据查询出来的学生的tid,寻找对应的老师 子查询
-->
<select id="getStudentList" resultMap="studentTeacherMap">
select s.id,s.name,s.tid from student s;
</select>
<resultMap id="studentTeacherMap" type="com.lwh.pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--
复杂的属性,我们需要单独处理
对象:association
集合:collection
-->
<association property="teacher" column="tid" javaType="com.lwh.pojo.Teacher" select="getTeacherList"/>
</resultMap>
<select id="getTeacherList" resultType="com.lwh.pojo.Teacher">
select t.id,t.name from teacher t;
</select>
</mapper>
按照结果嵌套处理
<select id="getStudentList2" resultMap="studentTeacherMap2">
select s.id sId, s.name sName, t.name tName from student s,teacher t where s.tid=t.id;
</select>
<resultMap id="studentTeacherMap2" type="com.lwh.pojo.Student">
<result property="id" column="sId"/>
<result property="name" column="sName"/>
<association property="teacher" javaType="com.lwh.pojo.Teacher">
<result property="name" column="tName"/>
</association>
</resultMap>
一对多处理
比如:一个老师拥有多个学生!
对于老师而言,就是一对多的关系!
环境搭建
// 学生实体类
@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> studentList;
}
按照结果嵌套处理
<select id="getTeacher" resultMap="teacherStudent" parameterType="int">
select t.id tId,t.name tName,s.id sId,s.name sName from teacher t ,student s where t.id = s.tid and t.id=#{tId}
</select>
<resultMap id="teacherStudent" type="com.lwh.pojo.Teacher">
<result property="name" column="tName"/>
<result property="id" column="tId"/>
<!--
复杂的属性,我们需要单独处理
集合:collection
javaType="" 执行属性的类型
结果中的泛型信息,我们使用ofType获取
-->
<collection property="studentList" ofType="com.lwh.pojo.Student">
<result property="id" column="sId"/>
<result property="name" column="sName"/>
</collection>
</resultMap>
按照查询嵌套处理
<select id="getTeacher2" resultMap="teacherStudent2" parameterType="int">
select id,name from teacher where id=#{tId}
</select>
<resultMap id="teacherStudent2" type="com.lwh.pojo.Teacher">
<collection property="studentList" javaType="ArrayList" ofType="com.lwh.pojo.Student" select="getStudentListByTeacherId" column="id"/>
</resultMap>
<select id="getStudentListByTeacherId" resultType="com.lwh.pojo.Student" parameterType="int">
select id,name,tid from student where tid=#{tId}
</select>
小结
-
关联 - association【多对一】
-
集合 - collection【一对多】
-
javaType & ofType
-
javaType 用来指定实体类中属性的类型
-
ofType 用来指定映射到List或者集合中pojo类型,泛型中的约束类型。
-
注意点
-
保证sql的可读性,尽量保证通俗易懂
-
注意一对多和多对一中,属性和字段的问题
-
如果问题不好排查错误,可以使用日志,建议使用Log4j
动态SQL
什么是动态sql:动态sql就是根据不同的条件生成不同的sql语句
-
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
DEFAULT CHARSET = utf8;
创建一个基础工程
-
导包
-
编写配置文件
-
编写实体类
// 实体类
@Data
public class Blog {
private String id;
private String title;
private String author;
private LocalDateTime createTime;
private int views;
}
4.编写实体类对应Mapper接口和Mapper.xml文件
if
<select id="getBlogList" parameterType="map" resultType="com.lwh.pojo.Blog">
select id,title,author,create_time createTime,views from blog
where 1=1
<if test="title != null">
and title like #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
choose (when, otherwise)----相当于switch
<select id="getBlogList" parameterType="map" resultType="com.lwh.pojo.Blog">
select id,title,author,create_time createTime,views from blog
<where>
<choose>
<when test="title != null">
title like #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</where>
</select>
trim (where, set)
where元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除
<select id="getBlogList" parameterType="map" resultType="com.lwh.pojo.Blog">
select id,title,author,create_time createTime,views from blog
<where>
<if test="title != null">
title like #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="title != null">
title=#{title},
</if>
<if test="author != null">
author=#{author}
</if>
</set>
where id=#{id}
</update>
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<trim prefix="SET" suffixOverrides=",">
...
</trim>
所谓的动态sql。本质还是sql语句,只是我们可以在sql层面,去执行一个逻辑代码
SQL片段
有的时候,我们可能会将一些功能的部分抽取出来,方便复用
-
使用sql标签抽取公共的部分
<sql id="title-author-views">
<choose>
<when test="title != null">
title like #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</sql>
2.在需要使用的地方使用include标签引用即可
<select id="getBlogList" parameterType="map" resultType="com.lwh.pojo.Blog">
select id,title,author,create_time createTime,views from blog
<where>
<include refid="title-author-views"/>
</where>
</select>
注意事项:
-
最好基于单表来定义sql片段
-
不要存在where标签
foreach
<!--
select id,title,author,create_time createTime,views from blog where 1=1 and (id ='1' or id='2'or id='3')
-->
<select id="getBlogListForeach" parameterType="map" resultType="com.lwh.pojo.Blog">
select id,title,author,create_time createTime,views from blog
<where>
<foreach collection="idList" item="id" open="(" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
动态sql就是在拼接sql语句,我们只要保证sql正确性,按照sql的格式,去排列组合就可以了
缓存
1.简介
-
什么是缓存[cache]
-
存在内存中的临时数据
-
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
-
-
为什么使用缓存
减少和数据库的交互次数,减少系统开销,提高系统效率 -
什么样的数据能使用缓存
经常查询并且不经常改变的数据
2.mybatis缓存
-
mybatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提高查询效率。
-
mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
-
默认情况下,只有一级缓存开启。(sqlsession级别的缓存,也称为本地缓存)
-
二级缓存需要手动开启和配置,它是基于namespace级别的缓存。
-
为了提高扩展性,mybatis定义了缓存接口cache。我们可以通过实现cache接口来自定义二级缓存。
-
3.一级缓存
-
一级缓存也叫本次缓存
-
与数据库同一次会话期间查询到的数据会放到本次缓存中。
-
以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库
-
一级缓存默认是开启的,只在一次sqlsession中有效,也就是拿到连接到关闭了连接这个区间段! 一级缓存就是一个map
4.二级缓存
-
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存。
-
基本namespace级别的缓存,一个名称空间,对应一个二级缓存
-
工作机制
-
一个会话查询一个数据,这个数据就会被放到当前会话的一级缓存中
-
如果当前会话关闭了,这个会话对应的一级缓存就没了,但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
-
新的会话查询信息,就可以直接从二级缓存中获取内容
-
不同的mapper查出的数据会放在自己对应的缓存(map)中
-
步骤
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--1.显式开启全局缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
<!--在当前mapper.xml中使用二级缓存-->
<cache/>
<!--也可以自定义参数-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
-
只要开启了二级缓存,在同一个Mapper下就有效
-
所有的数据都会先放在一级缓存中
-
只有当会话提交或者关闭的时候,才会提交到二级缓存中
5.缓存原理
-
先查询的二级缓存,查到直接返回
-
查不到,再查一级缓存,查到直接返回
-
查不到,查数据库