MyBatis延迟加载策略和MyBatis的缓存

1.什么是延迟加载?

延迟加载就是再需要用到数据时,才进行加载,不需要用到的数据时就不加载数据。延迟加载也称懒加载。

好处:

先从单表查询,需要时再从关联表去关联查询,大大提高了数据库性能,因为查询单表要比关联查询多张表速度要快。

坏处:

因为只有当需要用到数据时,才会进行数据库查询,这样在大批量得的数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验感下降。

所谓的懒加载就是把sql查询语句分成了两步 用select去连接另一个表的查询语句(一对一), 如果要查stuent表的内容就要通过懒加载 这里column定义了共有属性(变量) studentid

column在association 和 collection标签中都十分重要

第一步:开启懒加载

这里将回忆mybatis一对一,一对多,多对多中出现的resultMap集合所遗漏的知识点
首先讲:一对一懒加载[ “id”":为resultMap集合的地址, “type”" 为对应的实体类 (类型)(大小写无所谓), “property” 为实体类中对应的变量(对象)]
["column"为sql表中对应的属性名]
["association"为一对一的标签, “property” 为实体类中对应的变量(对象),列:另一个实体类的对象private Student student;, "javaType"为该对象的参数类型(类型)(大小写无所谓)
,“select"调用查询该对象的 “全限定名””+“方法名”]
[assocaistion中的"column" 指的是一对一两个sql表中用来关联的属性名(一般指id),例如:studentid]
[fetchType:懒加载两个值(lazy或者eager)]

<resultMap id=""  type = "">
     <id property="" column=""></id>
     <result property = "" column = ""></reslut>
     .
     .
     .
     <association property="" javaType="" select"" column="" fetchType = ""
     </association>
                    
</resultMaop>

这里讲一对多的懒加载中用到的collection 标签
[因为collection标签后的property为一个集合对象,所以不需要javaType]

<resultMap id=""  type = "">
     <id property="" column=""></id>
     <result property = "" column = ""></reslut>
     .
     .
     .
      <collection property=""  column="" select="" fetchType = "" 
     </collection>
     </resultMaop>

普通的collection标签 和 association标签

 <resultMap id="findAllGoodsWithcategoryMap" type="Goods">
    <association property="category" column="categoryid" javaType="Category">
     </association>
 </resultMap>

<resultMap id="categoryWithGoodsMap" type="category">
   <collection property="goodsList" ofType="goods">
   </collection>
 </resultMap>

代码演示

在mybatisconfig.xml 配置里 vlue有 true 和 false 两种属性

<settings>
<!-- 开启全局懒加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>

注意事项:

懒加载分为两种:
第一种:一对一association延迟加载 第二种一对多collection延迟加载

select:为我们调用其他映射的id
column:为传递的参数
javaType:为查询到的java 数据类型
fetchType:是否使用懒加载,如果不设置与全局设置保持一致

MyBatis延迟加载策略和MyBatis的缓存_第1张图片

一对一懒加载演示

ScoreDao


List<Score> findAllScoreWithStudent();

IStudentDao

IStudentDao:Student findStudentById(int id);

ScoreDao.xml

<?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">
<!--
xml;映射文件
-->
<mapper namespace="com.aaa.dao.ScoreDao">
    <!--开启二级缓存-->
    <cache >
        <property name="eviction" value="LRU" />
        <property name="flushInterval" value="600" />
        <property name="size" value="1024" />
        <property name="readOnly" value="false" />
    </cache>



    <select id="findScoreByStudentId" parameterType="Score"  resultType="score">
        select * from score where studentid = #{studentid}
    </select>


    <!--  定义封装  -->
    <resultMap id="findAllScoreWithStudentLazyMap" type="score">
        <id property="scoreid" column="scoreid"></id>
        <result property="score" column="score"></result>
        <result property="coursename" column="coursename"></result>
        <result property="studentid" column="studentid"></result>
       <!-- <result property="studentid" column="studentid"></result>    这一行是否都不写?  还是在Lazy中不写?-->
        <!-- 所谓的懒加载就是把sql查询语句分成了两步   用select去连接另一个表的查询语句(一对一)-->
        <association property="student" javaType="student"   select="com.aaa.dao.IStudentDao.findStudentById" column="studentid"
       fetchType="lazy"  ></association>


    </resultMap>
   <!-- scoreid  coursename studentid score -->
    <!-- 如果要查stuent表的内容就要通过懒加载   这里column定义了共有属性(变量) studentid -->
   <select id="findAllScoreWithStudent" resultMap="findAllScoreWithStudentLazyMap">
       select  * from  Score

   </select>

</mapper>

测试

public class MyBatisLazyTest {
    private SqlSession sqlSession;
    @Before   //在test 注解之前  调用
    public void init() {
        InputStream inputStream=null;
        try {
            inputStream =  Resources.getResourceAsStream("mybatisconfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory =  builder.build(inputStream);
        sqlSession =  sqlSessionFactory.openSession(true);

    }
    /*
     *@Author lee
     *@time:2020/7/11 10:41
     *注释:一对一
     */
    @Test
    public void findAllScoreWithStudentLazyTest(){
        /*加载实现类*/
        ScoreDao scoreDao = sqlSession.getMapper(ScoreDao.class);
        List<Score> scoreList = scoreDao.findAllScoreWithStudent();
        for (Score score:scoreList){
            /*System.out.println("Score:"+score.getCoursename());*/ /*有懒加载*/
            /*System.out.println("Student:"+score.getStudentid());*/
            System.out.println("Student:"+score.getStudent());
        }
    }

一对多

IStudentDao

List<Student> findAllStudentWithScore();

ScoreDao

Score findScoreByStudentId(int studentid);

IStudentDao.xml

<?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">

<!--
xml;映射文件
-->
<mapper namespace="com.aaa.dao.IStudentDao">
    <!--开启二级缓存-->
    <cache >
        <property name="eviction" value="LRU" />
        <property name="flushInterval" value="600" />
        <property name="size" value="1024" />
        <property name="readOnly" value="false" />
    </cache>

<!-- parameter是参数类型   resultType是返回值类型 -->
  <select id="findStudentById" resultType="student">
      select *  from student where id = #{id}
  </select>
    <resultMap id="findAllStudentWithRoleLazyMap" type="student">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="sex" column="sex"></result>
        <result property="age" column="age"></result>
        <result property="height" column="height"></result>
        <!-- 所谓的懒加载就是把sql查询语句分成了两步  用select去连接另一个表的查询语句(一对多)-->
        <collection property="scoreList" column="id"  select="com.aaa.dao.ScoreDao.findScoreByStudentId" fetchType="lazy">

        </collection>
    </resultMap>
    <!-- id   name sex  age height  listscore-->
    <!-- 如果要查 listscore 就要通过懒加载,但是个一对多在实体中加的list集合所以没有column这个共有属性(变量)-->
    <select id="findAllStudentWithScore" resultMap="findAllStudentWithRoleLazyMap">
               select  * from  student
    </select>
</mapper>

MyBatisLazyTest

public class MyBatisLazyTest {
    private SqlSession sqlSession;
    @Before   //在test 注解之前  调用
    public void init() {
        InputStream inputStream=null;
        try {
            inputStream =  Resources.getResourceAsStream("mybatisconfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory =  builder.build(inputStream);
        sqlSession =  sqlSessionFactory.openSession(true);

    }
   
    /*
     *@Author lee
     *@time:2020/7/11 10:48
     *注释:多对多懒加载
     */
    @Test
    public void findAllStudentWithScoreLazyTest(){
        /*加载实现类*/
        IStudentDao iStudentDao = sqlSession.getMapper(IStudentDao.class);
        List<Student> studentList = iStudentDao.findAllStudentWithScore();
        for (Student student :studentList){
            System.out.println("student:"+student);
            System.out.println("student:"+student.getId());
            System.out.println("ScoreList:"+student.getScoreList());
        }
        }
    }

2.MyBatis的缓存

缓存的作用|缓存:1.提高加载速度 2.减轻服务(web,mysql)压力

一级二级缓存调用顺序:先查二级缓存,再查一级缓存,再查数据库;即使在一个sqlSession中,也会先查二级缓存;一个namespace中的查询更是如此;

使用二级缓存的实体类必须实现序列化;方便存储

级缓存;一个namespace中的查询更是如此;
使用二级缓存的实体类必须实现序列化;方便存储
缓存是一般的ORM框架都会提供的功能,目的就是提升查询的肖略和减少数据库的压力。跟Hibernate一样,MyBatis也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口。

MyBatis的缓存分为两种
一级缓存基于sqlSession 二级缓存基于namespace
缓存的作用 缓存:1.提高加载速度 2.减轻服务(web,mysql)压力
关于脏数据 因为当一级二级缓存都开启的时候,会发生数据碰撞,但是当运行二级缓存的时候,关闭一级缓存就不产生脏数据
一级二级缓存用的测试是不同的 因为要测试多个Sqlsessioon,进行数据的查询修改,看数据会不会发生改变

MyBatis延迟加载策略和MyBatis的缓存_第2张图片

开启二级缓存,触发二级缓存需要sqlSession.commit()提交或者sqlSession.close()关闭

<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
 private SqlSessionFactory sqlSessionFactory;
    @Before  //在Test   注解调用之前调用
    public void init(){
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream("mybatisconfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*SqlSessionFactoryBuilder 是建造者模式*/
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        /* 创建 mybatis 连接 mysql 的工厂 相当于  创建 jdbc中的connect工厂*/
        sqlSessionFactory = builder.build(inputStream);
    }
@Test
    public  void secondCacheTest(){

        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        IStudentDao iStudentDao1 =   sqlSession1.getMapper(IStudentDao.class);
       Student student1 =  iStudentDao1.findStudentById(1);
       System.out.println("student1:"+student1);
       // 提交 触发 二级缓存生效
       // 发生更新,二级缓存失效
       student1.setAge(77);
       iStudentDao1.updateStudent(student1);
       sqlSession1.commit();
       IStudentDao iStudentDao2 =   sqlSession2.getMapper(IStudentDao.class);
       Student student2 = iStudentDao2.findStudentById(1);
       System.out.println("student2:"+student2);
   }

关闭一级缓存(关闭一级缓存的作用,避免脏数据的产生)

 <!--关闭一级缓存-->
        <setting name="localCacheScope" value="STATEMENT"/>

解决一级缓存时,产生的问题toString();

  <!--解决  懒加载时:  打印对象toString 触发 懒加载
      lazyLoadTriggerMethods : 指定那个对象的方法触发一次延迟加载,默认值:equal
      System.out.println("student:"+student)  因为直接便利对象的时候会触发懒加载,所以引入"lazyLoadTriggerMethods"解决-->

        <setting name="lazyLoadTriggerMethods" value="false"/>

二级缓存经常忘记的事情(需要手动调整flushInterval时间,进行缓存刷新,保证数据的新鲜性)

<mapper namespace="com.wgz.dao.IStudentDao">
<!--开启二级缓存-->
<cache >
<property name="eviction" value="LRU" />
<property name="flushInterval" value="6000000" />
<property name="size" value="1024" />
<property name="readOnly" value="false" />
</cache>
</mapper>

使用缓存:useCahce默认属性为true

<!--使用resultMap-->
<select id="findStudentById" parameterType="java.lang.Integer" resultType="student"
useCache="true">
select * from student_tb where id=#{id}
</select>

一级缓存是SqlSession
二级缓存是mapper(整个namespace命名空间)

详细一二级缓存访问流程图

MyBatis延迟加载策略和MyBatis的缓存_第3张图片

你可能感兴趣的:(mybatis)