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和缓存

mybatis 详解------动态SQL

mybatis 详解------动态SQL

Mybatis学习动态加载一二级缓存

Mybatis -- 动态Sql概述动态Sql之<if>(包含<where>)动态Sql之<foreach>sql片段抽取