Mybatis复杂查询动态sql及缓存详解
Posted 3 ERROR(s)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis复杂查询动态sql及缓存详解相关的知识,希望对你有一定的参考价值。
文章目录
一、多对一
实体类:
import lombok.Data;
@Data
public class Student {
private int id;
private String name;
private Teacher teacher;
}
import lombok.Data;
@Data
public class Teacher {
private int id;
private String name;
}
Studentmapper接口:
public interface Studentmapper {
public List<Student> getStudent();
}
Studentmapper.xml映射文件
按照查询嵌套查询
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="entity.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher" >
select * from teacher where id=#{tid}
</select>
按照查询结果嵌套查询
<select id="getStudent" resultMap="Studentteacher">
select s.id sid,s.name sname,t.id tid,t.name tname
from student s,teacher t
where s.tid=t.id;
</select>
<resultMap id="Studentteacher" type="entity.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="entity.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
Test测试类
public void getTeacher(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
Studentmapper mapper = sqlSession.getMapper(Studentmapper.class);
List<Student> student = mapper.getStudent();
for (Student student1 : student) {
System.out.println(student1);
}
sqlSession.commit();
sqlSession.close();
查询结果:
Student(id=1, name=董xx, teacher=Teacher(id=1, name=老王))
Student(id=2, name=李沫x, teacher=Teacher(id=1, name=老王))
Student(id=3, name=马x林, teacher=Teacher(id=1, name=老王))
Student(id=4, name=马x狗, teacher=Teacher(id=2, name=老哥))
Student(id=5, name=李狗x, teacher=Teacher(id=2, name=老哥))
二、一对多
实体类
@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;
}
Teachermapper接口:
public interface Teachermapper {
Teacher getTeacher(@Param("tid") int id);
}
Teachermapper.xml文件:
因为一个老师有多个学生,所以
<select id="getTeacher" resultMap="teacherStudent">
select s.id sid,s.name sname, t.id tid,t.name tname
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"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
- 其中复杂的属性要单独处理,集合用collection,对象用association
- javaType="" 指定属性的类型
- ofType ="" 获取集合中的泛型
Test测试类
@Test
public void getTeacher(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
Teachermapper mapper = sqlSession.getMapper(Teachermapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
sqlSession.commit();
sqlSession.close();
}
}
查询结果
Teacher(id=1, name=老王, students=[Student(id=1, name=董瑞龙, tid=1), Student(id=2, name=李沫璇, tid=1), Student(id=3, name=马嘉林, tid=1)])
三、动态sql
3.1 什么是动态sql
- 动态sql就是根据不同的条件生成不同的sql语句。
- 本质还是一句sql,只不过我们可以再sql层面执行一个逻辑代码
3.2 if标签
作用:标签用if标签进行判断然后拼接,用if标签时,要给原本的SQL语句后加一个"where 1=1" 以便后面进行SQL拼接。
Bookmapper接口:
public interface Bookmapper {
List<Book> dongtaisqlIF(Map<String,String> map);
}
Bookmapper.xml文件:
<select id="dongtaisqlIF" parameterType="map" resultType="Book" >
select * from book where 1=1
<if test="title!=null">
and title =#{title}
</if>
<if test="author!=null">
and author =#{author}
</if>
</select>
Test测试类:
public void dongtaisqlIF()
{
SqlSession sqlSession = MybatisUtil.getSqlSession();
Bookmapper mapper = sqlSession.getMapper(Bookmapper.class);
Map<String,String> map=new HashMap<>();
map.put("title","语文书");
List<Book> books = mapper.dongtaisqlIF(map);
for (Book book : books) {
System.out.println(book);
}
sqlSession.commit();
sqlSession.close();
}
查询结果
ook(id=4558e13487194a4196e2876f3ea72097, title=语文书, author=董瓜皮, createTime=Thu Oct 21 16:31:40 CST 2021, views=123)
Book(id=624ba970bac949f3a257c83a3d54b3de, title=语文书, author=董瓜皮, createTime=Thu Oct 21 16:28:05 CST 2021, views=2000)
3.3 where标签
根据刚才的动态sql语句我们可以得知我们经常在动态构造sql时,为防止注入或防止语句不当时会使用where 1=1,但这并不合适。所以我们引入了where标签。
where标签会知道如果它包含的标签中有返回值的话,它就会插入一个‘where’。此外,如果标签返回的内容是以AND 或OR开头的,则会把它去除掉。
3.4 choose(when otherwise)标签
<select id="dongtaisqlIF" parameterType="map" resultType="Book" >
select * from book
<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>
进入choose标签之后,按顺序只对一个标签中的sql语句进行查找,若都不满足则对中的语句进行查找。
例1:我传入三个数据,但是只对title进行了查询。
public void dongtaisqlIF()
{
SqlSession sqlSession = MybatisUtil.getSqlSession();
Bookmapper mapper = sqlSession.getMapper(Bookmapper.class);
Map<String,String> map=new HashMap<>();
map.put("title","语文书");
map.put("author","皮");
map.put("views","1000");
List<Book> books = mapper.dongtaisqlIF(map);
for (Book book : books) {
System.out.println(book);
}
sqlSession.commit();
sqlSession.close();
}
返回的结果是title为语文书的所有对象
Book(id=4558e13487194a4196e2876f3ea72097, title=语文书, author=董瓜皮, createTime=Thu Oct 21 16:31:40 CST 2021, views=123)
Book(id=624ba970bac949f3a257c83a3d54b3de, title=语文书, author=董瓜皮, createTime=Thu Oct 21 16:28:05 CST 2021, views=2000)
3.5 sql片段
sql片段可以用来解决重复造轮子的问题
<sql id="hhhhh" >
<if test="title!=null">
and title =#{title}
</if>
<if test="author!=null">
and author =#{author}
</if>
</sql>
使用标签将需要复用的sql片段插入。
<select id="dongtaisqlIF" parameterType="map" resultType="Book" >
select * from book
<where>
<include refid="hhhhh"></include>
</where>
</select>
3.6 Foreach
open:开始的标志
close:结束的标志
separator:用什么隔开
collection:
item:
<select id="FOReach" parameterType="map" resultType="book">
select * from book
<where>
<foreach collection="ids" item="id" open="(" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
测试文件:
public void FOReach(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
Bookmapper mapper = sqlSession.getMapper(Bookmapper.class);
HashMap map = new HashMap<>();
ArrayList<Integer> ids= new ArrayList<>();
ids.add(1);
map.put("ids",ids);
List<Book> books1 = mapper.FOReach(map);
for (Book book : books1) {
System.out.println(book);
}
开始
四、缓存
4.1什么是缓存?
- 存在内存中的临时数据
- 将用户经常查询的数据放在缓存中(内存),用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,转而从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
4.2为什么使用缓存?**
- 减少和数据库的交互此数,减少系统开销,提高系统效率。
4.3什么样的数据能使用缓存?
- 经常查询且不经常改变的数据。
4.4.测试实现一级缓存
接口:
public interface Teachermapper {
Teacher getTeacher( int id);
}
映射文档:
<select id="getTeacher" parameterType="java.lang.Integer" resultType="entity.Teacher">
select * from teacher where id =#{tid}
</select>
测试类:
public void getTeacher(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
Teachermapper mapper = sqlSession.getMapper(Teachermapper.class);
Teacher teacher = mapper.getTeacher(1);
Teacher teacher2 = mapper.getTeacher(1);
System.out.println(teacher);
System.out.println("=====================");
System.out.println(teacher2);
System.out.println(teacher==teacher2);
}
我们可以看到我们的sql只执行了一次,但是我们的两次查询结果是相同的,也就是说第二次的查询直接是在缓存中读取的。
4.5二级缓存
- 二级缓存也叫全局缓存,因为一级缓存的作用域太小了,所以单身了耳机缓存。
- 基于namespace级别的缓存,一个名称空间对应一个二级缓存。
- 工作机制
一个会话查询一条数据,这个数据就回被放在当前会话的一级缓存中;
如果当前会话关闭了,这个会话对应的一级缓存就没了,但是我们想要的是,会话关闭数据被保存到二级缓存中。
新的会话查询信息,就可以直接在二级缓存中查找
(1)开启全局缓存
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
(2)在要使用二级缓存的mapper中使用
(3)二级缓存工作原理
用户先读取二级缓存再读取一级缓
以上是关于Mybatis复杂查询动态sql及缓存详解的主要内容,如果未能解决你的问题,请参考以下文章
Mybatis关于复杂的SQL查询的处理&Mybatis的缓存机制
Mybatis -- 动态Sql概述动态Sql之<if>(包含<where>)动态Sql之<foreach>sql片段抽取