mybatis学习第三天

1.mybatis延迟加载策略

什么是延迟加载?

延迟加载就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处: 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

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

开启懒加载

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

association延迟加载

1.在IScoreDao接口中增加

  List<Score> findAllScoreWithStudentLazy();

2.在IScoreDao.xml 中增加


    <!-- 定义封装StudentScore和user的resultMap -->
    <resultMap id="findAllScoreWithStudentLazyMap" type="Score">
        <id property="scoreid" column="scoreid"></id>
        <result property="coursename" column="coursename"></result>
        <result property="score" column="score"></result>

        <!-- 一对一的关系映射:配置封装Student的内容-->
        <association property="student"  javaType="Student"
                     select="com.wgz.dao.IStudentDao.findStudentById" column="studentid" fetchType="lazy">
        </association>
    </resultMap>


    <select id="findAllScoreWithStudentLazy" resultMap="findAllScoreWithStudentLazyMap">
            select * from score_tb;
    </select>

select:为我们调用其他映射的id

column:为传递的参数

javaType:为查询到的java 数据类型

fetchType:是否使用懒加载,如果不设置与全局设置保持一致

3.测试

  IScoreDao scoreDao = sqlSession.getMapper(IScoreDao.class);

            List<Score> scoreList =  scoreDao.findAllScoreWithStudentLazy();
            for (Score score:scoreList){
                // 不调用学生相关信息,不请求查数据库
                System.out.println("score:"+score.getScore());
                // 调用学生信息,发起二次请求查询学生相关的数据库
                //System.out.println("student:"+score.getStudent());
            }

collection延迟加载

1.在IStudentDao增加

     /**
      * 延迟加载学生的成绩
      * @return
      */
     List<Student>  findAllStudentWithScoreListLazy();

2.在IStudentDao.xml 中增加

  <!--
        一对多懒加载
    -->
    <resultMap id="findAllStudentWithScoreListLazyMap" type="Student">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="sex" column="name"></result>
        <result property="age" column="age"></result>
        <result property="height" column="height"></result>
        <result property="birthday" column="birthday"></result>


        <collection property="scoreList" column="id" select="com.wgz.dao.IScoreDao.findScoreByStudentId" fetchType="lazy">
        </collection>

    </resultMap>

    <select id="findAllStudentWithScoreListLazy" resultMap="findAllStudentWithScoreListLazyMap">
                select * from student_tb
    </select>

3.测试


            // 方式一 通过代理:
            IStudentDao studentDao = sqlSession.getMapper(IStudentDao.class);

            List<Student> studentList =  studentDao.findAllStudentWithScoreListLazy();
            for (Student student:studentList){
                // 不调用学生成绩相关信息,不请求查数据库
                System.out.println("Student:"+student.getName());
                // 调用学生成绩信息,发起二次请求查询学生成绩相关的数据库
                System.out.println("ScoreList:"+student.getScoreList());
            }
            

2.mybatis的缓存

缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力。跟Hibernate 一样,MyBatis 也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口。

img

一级缓存基于sqlSession,二级缓存基于namespace

一级缓存

一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。一旦发生增删改,缓存立即失效

img

测试

           IStudentDao studentDao = sqlSession.getMapper(IStudentDao.class);

            // 两次查询操作,只有第一次调用sql
            Student student =  studentDao.findStudentById(45);
            student = studentDao.findStudentById(45);

            Student student1 = new Student();
            student1.setName("xiaoming");
            student1.setId(46);
            student1.setSex("F");

//            studentDao.updateStudent(student1);
//            System.out.println("----------------");

            //清空缓存
            sqlSession.clearCache();
            //当同一个session 发生了 增删改时 那么换粗立即失效 ===  sqlSession.clearCache();
            student = studentDao.findStudentById(45);

二级缓存

二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个
SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

缓存流程图

img

img

二级缓存的开启

1.在mybatis开启

    <settings>

        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

2.在mapper 中开启二级缓存

<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>    
  • eviction
    缓存回收策略,有这几种回收策略
    • LRU - 最近最少回收,移除最长时间不被使用的对象
    • FIFO - 先进先出,按照缓存进入的顺序来移除它们
    • SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
    • WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象

默认是 LRU 最近最少回收策略

  • flushinterval 缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值
  • readOnly: 是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 觉得数据可能会被修改
  • size : 缓存存放多少个元素
  • type: 指定自定义缓存的全类名(实现Cache 接口即可)
  • blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。

3.使用缓存

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


4测试

    // 3.获取session
            SqlSession sqlSession1 = sqlSessionFactory.openSession();

            //  4.使用sqlSession 创建代理对象
            IStudentDao studentDao1 = sqlSession1.getMapper(IStudentDao.class);


            Student student1 =  studentDao1.findStudentById(45);
            System.out.println("student1:"+student1);
            //清空缓存
            sqlSession1.close();

            // 获取新的SqlSession 但是sql 语句没有执行,这是应为 可以去二级缓存去取,多个session 共享缓存
            SqlSession sqlSession2 = sqlSessionFactory.openSession();
            IStudentDao studentDao2  =  sqlSession2.getMapper(IStudentDao.class);
            Student student2=studentDao2.findStudentById(45);
            System.out.println("student2:"+student2);

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

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

3mybatis基于注解的开发

mybatis常用注解

@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用

基于注解的增删改查


    /**
     * 查找所有学生
     * @return
     */
    @Select({"select * from student_tb"})
    @Results(id = "studentMap",value = {@Result(id = true,property = "id",column = "id"),
            @Result(property = "name",column = "name"),
            @Result(property = "sex",column = "sex"),
            @Result(property = "age",column = "age"),
            @Result(property = "height",column = "height"),
            @Result(property = "birthday",column = "birthday")
    })
    List<Student> findAllStudent();




    /**
     * 根据 查询学生
     * @param id
     * @return
     */
    @Select("select * from student_tb where id = #{id}")
    @ResultMap(value = "studentMap")
    Student findStudentById(int id);


    /**
     * 保存学生
     * @param student
     */
    @Insert(" insert into  student_tb (name,age,sex,height,birthday)values (#{name},#{age},#{sex},#{height},#{birthday})")
    @SelectKey(keyColumn = "id",keyProperty = "id",resultType = Integer.class,before = false,statement = " select last_insert_id()")
    int saveStudent(Student student);


    /**
     * 删除学生
     * @param id
     * @return
     */
    @Delete("delete from student_tb where id = #{id}")
    int deleteStudentById(int id);

    /**
     * 更新学生
     * @param student
     * @return
     */
    @Update("update student_tb set name=#{name},age=#{age},height=#{height},sex=#{sex},birthday=#{birthday} where id=#{id}")
    int updateStudent(Student student);



    /**
     * 根据名称模糊查询
     * @param likeName
     * @return
     */
    @Select("  select  * from  student_tb where  name like  #{likeName}")
    @ResultType(Student.class)
    List<Student> findStudentListByName(String likeName);

复杂映射的开发

@Results 注解
	代替的是标签<resultMap>
	该注解中可以使用单个@Result 注解,也可以使用@Result 集合
	@Results({@Result(), @Result() })或@Results(@Result())
@Resutl 注解
	代替了 <id>标签和<result>标签
	@Result 中 属性介绍:
	id 是否是主键字段
	column 数据库的列名
	property 需要装配的属性名
	one 需要使用的@One 注解(@Result(one=@One)()))
	many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
	代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
	@One 注解属性介绍:
		select 指定用来多表查询的 sqlmapper
		fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
		使用格式:
		@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)
	代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
	注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
	(一般为 ArrayList)但是注解中可以不定义;
	使用格式:
		@Result(property="",column="",many=@Many(select=""))
一对一复杂关系映射

IScoreDao2的注解配置,使用one代替assocation

public interface IScoreDao2 {


    @Select("select * from score_tb where studentid = #{studentid}")
    @ResultType(Score.class)
    Score findScoreById(int studentid);


    @Select("select * from score_tb")
    @Results(id = "scoreMap1",value = {
            @Result(id = true,property = "scoreid",column ="scoreid" ),
            @Result(property = "coursename",column ="coursename" ),
            @Result(property = "score",column ="score" ),
            @Result(property = "student",column = "studentid",one = @One(select = "com.wgz.dao.IStudentDao.findStudentById",fetchType = FetchType.LAZY))
    })
    List<Score> findAllScoreWithStudentOne();


}

一对多注解式懒加载

IStudentDao2配置


    @Select("select  * from  student_tb")
    @Results(id = "studentMap2",value = {@Result(id = true,property = "id",column = "id"),
        @Result(property = "sex",column = "sex"),
            @Result(property = "age",column = "age"),
            @Result(property = "height",column = "height"),
            @Result(property = "birthday",column = "birthday"),
            @Result(property = "scoreList",column = "id",many = @Many(select = "com.wgz.dao.IScoreDao2.findScoreById",fetchType = FetchType.LAZY)),
    })
    List<Student>  findAllStudentWithScoreList();


注解式开启缓存

// 开启缓存
@CacheNamespace(blocking = true)

olumn = “age”),
@Result(property = “height”,column = “height”),
@Result(property = “birthday”,column = “birthday”),
@Result(property = “scoreList”,column = “id”,many = @Many(select = “com.wgz.dao.IScoreDao2.findScoreById”,fetchType = FetchType.LAZY)),
})
List findAllStudentWithScoreList();


### 注解式开启缓存

// 开启缓存
@CacheNamespace(blocking = true)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值