写在前面:分享技术,共同进步,有不足请见谅,相关意见可评论告知 ~
编程路漫之远兮,运架构体之帷幄;
劝君专注案前事,亦是杯酒敬苍生;
多对一处理
测试环境搭建
-
导入lombok
-
新建实体类 Teacher,Student
-
建立Mapper接口
-
建立Mapper.XML文件
-
在核心配置文件中绑定注册我们的Mapper接口或者文件!【方式很多,随心选】
-
测试查询是否能够成功!
搭建图解:
原始数据库SQL 操作:
按照查询嵌套处理
解决两个内容无法连接的问题(即有一个属性为空)
<!--
思路:
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 -->
<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 多对一查询方式:
- 子查询
- 联表查询
一对多处理
前序:一对多关系一般都由多端维护系统关系
环境搭建
同上
实体类
@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 student s,teacher t
where s.tid = t.id 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">
<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>
小结
- 关联 - association 【多对一】
- 集合 - collection 【一对多】
- javaType & ofType
- JavaType 用来指定实体类中属性的类型
- ofType 用来指定映射到List或者集合中的 pojo类型,泛型中的约束类型!
注意点:
- 保证SQL的可读性,尽量保证通俗易懂
- 注意一对多和多对一中,属性名和字段的问题!
- 如果问题不好排查错误,可以使用日志 , 建议使用 Log4j
动态 SQL
什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
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 int id; private String title; private String author; private Date createTime; private int views; }
-
编写实体类对应Mapper接口 和 Mapper.XML文件
Tips:解决Idea拼写不符合规范问题(波浪线提示)
@SuppressWarnings("all")
编写随机ID工具类
配置数据库字段名与实体类中的兼容问题
利用驼峰式命名解决
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>
类似于 switch....case
trim (where,set)
select * from mybatis.blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
<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 , set , choose ,when
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 mybatis.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 collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了
SQL片段
功能的部分抽取出来,方便复用
-
使用SQL标签抽取公共的部分
<sql id="if-title-author"> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </sql>
-
在需要使用的地方使用Include标签引用即可
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <include refid="if-title-author"></include> </where> </select>
注意事项:
- 最好基于单表来定义SQL片段!
- 不要存在where标签
缓存
简介
缓存 [ Cache ]
存在内存中的临时数据,将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决高并发系统的性能问题。以减少和数据库的交互次数,减少系统开销,提高系统效率。
Mybatis缓存
系统定义两级缓存:一级缓存和二级缓存
-
默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
-
二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
-
为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
一级缓存
又名本地缓存: SqlSession
与数据库同一次会话期间查询到的数据会放在本地缓存中, 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
测试步骤:
- 开启日志!
- 测试在一个Sesion中查询两次相同记录
- 查看日志输出
缓存失效的情况:
-
查询不同的东西
-
增删改操作,可能会改变原来的数据,所以必定会刷新缓存!
3.手动清除缓存
sqlSession.clearCache()
小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段!一级缓存就是一个Map。
二级缓存
- 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
- 工作机制
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
步骤:
-
开启全局缓存
<!--显示的开启全局缓存--> <setting name="cacheEnabled" value="true"/>
-
在要使用二级缓存的Mapper中开启
<!--在当前Mapper.xml中使用二级缓存--> <cache/>
也可以自定义参数
<!--在当前Mapper.xml中使用二级缓存--> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
-
测试
-
问题:我们需要将实体类序列化!否则就会报错!
Caused by: java.io.NotSerializableException: com.kuang.pojo.User
-
小结:
- 只要开启了二级缓存,在同一个Mapper下就有效
- 所有的数据都会先放在一级缓存中;
- 只有当会话提交,或者关闭的时候,才会提交到二级缓冲中!
缓存原理
Redis数据库来做缓存 K-V
常见异常及错误
①关于无法new java类错误
现象:只有file
,没有java class
如下图
解法:因为该不在可编译的目录下,可在 Project Structure 中进行设置
②关于Test测试
(1)下图情况
方法错误(即写的不是方法 eg: 少了方法的括号)
(2)没有导入包 import org.junit.Test;
③关于数据库查询xml文件提示
(1)波浪线为正常
(2)里面包含的有些SQL语句是不加 ;
④Mapper接口中未创建方法
下图为在测试代码中
解法如下图:
⑤resultType 与resultMap
Caused by: org.apache.ibatis.type.TypeException: Could not resolve type alias 'Student'. Cause: java.lang.ClassNotFoundException: Cannot find class: Student
原因:将resultMap写成了resultType,Type对应的是对象类,所以抛出ClassNotFoundException的异常,mybatis的结果是存放在resultMap中的。
⑥类找不到异常(*)
Could not resolve type alias 'Student'. Cause: java.lang.ClassNotFoundException: Cannot find class: Student
原因分析:找不到类替代的别名,在mybatis-config.xml
,漏写typeAliases
解决:
基于实战中学习,学习快乐中成长
.
时间会回答成长,成长会回答梦想