框架学习 二 Mbatis、03(maven,mybatis,spring,springmvc)

1.懒加载

一对多懒加载

在这里插入图片描述

1.mybatis配置中开启懒加载
    <!-- 开启全局懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
2.查询所有学生
    /**
     * 查找学生 并查看学生的成绩
     * 一对多懒加载
     * @return
     */
    List<Student> findAllStudentWithScoreLazy();

<!--
    一对多懒加载
    1.查询所有的学生 select * from student_tb
    2.根据学生的 id 查找到所有相关学生的成绩 列表

    <collection property="scoreList" column="id" ofType="Score" 
    select="com.qfedu.dao.ScoreDao.findAllScoreByStudentId">
    property="scoreList"  Student 类中的  成绩列表属性
    ofType="Score"  集合中放置的类型
    column="id"  学生id  数据表列名、
   select="com.qfedu.dao.ScoreDao.findAllScoreByStudentId" 调用ScoreDao 中对应的方法并且 将 student表中列名 id 学生id对应的值给到这个方法
    -->

    <resultMap id="studentWithScoreLazyMap" type="Student">
        <id column="id" property="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="height" column="height"></result>
        <result property="sAddress" column="s_address"></result>


        <collection property="scoreList" column="id" ofType="Score" select="com.qfedu.dao.ScoreDao.findAllScoreByStudentId">

        </collection>

    </resultMap>

    <select id="findAllStudentWithScoreLazy" resultMap="studentWithScoreLazyMap">
        select * from student_tb
    </select>
3.当需要查询学生成绩时调用
public interface ScoreDao {


    /**
     * 根据学生的id 去查询该学生的列表
     * @param id
     * @return
     */
    List<Score> findAllScoreByStudentId(int id);

}

<?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">
<mapper namespace="com.qfedu.dao.ScoreDao">



    <select id="findAllScoreByStudentId" resultType="Score">

        select * from score_tb where studentid = #{id}

    </select>

</mapper>
测试
    @Test  // 一对多懒加载
    public void  findAllStudentWithScoreLazyTest(){


        List<Student> studentList =   studentDao.findAllStudentWithScoreLazy();

        for (Student student:studentList){
            System.out.println("student-name:"+student.getName());
            // 懒加载 只有当调用时 student.getScoreList() 才去请求查询学生成绩
            System.out.println("student-scoreList:"+student.getScoreList());

            // 一旦调用 student的 toString 就会触发懒加载
            //mybatis 底层机制只要 触发equals,clone,hashCode,toString 就会懒加载
            // 可以再setting 里面关闭功能
            System.out.println("student:"+student);
        }

    }

一对一懒加载

查看所有成绩,并在需要时查看改成绩对应的学生信息

1.先查出来所有的成绩列表
    /**
     * 查询所有的成绩 并再需要时包含 该成绩对应的学生
     * @return
     */
    List<Score> findAllScoreWithStudentByLazy();


    <!--
        一对一 懒加载
        1.查询所有成绩    select * from score_tb
        2.当需要成绩对应的学生信息时
        执行 一对一
        <association property="student" column="studentid"
                     javaType="Student" select="com.qfedu.dao.StudentDao.findStudentById">

        property="student" Score 类中的student 属性
        column="studentid"       成绩表中 学生id 的列名
        javaType="Student"  返回的类型
        select="com.qfedu.dao.StudentDao.findStudentById" 当需要改学生的信息时调用此方法 并且经对应studentid 的值传给他
    -->
    <resultMap id="scoreWithStudentByLazyMap" type="Score">
        <id column="scoreid" property="scoreid"></id>
        <result column="couresename" property="couresename"></result>
        <result column="score" property="score"></result>
        <result column="studentid" property="studentid"></result>

        <association property="student" column="studentid"
                     javaType="Student" select="com.qfedu.dao.StudentDao.findStudentById">

        </association>

    </resultMap>

    <select id="findAllScoreWithStudentByLazy" resultMap="scoreWithStudentByLazyMap">
        select * from score_tb
    </select>
2.再需要时 差选该成绩对应的学生信息
   /**
     * 根据id 查找学生
     * @param id
     * @return
     */
    Student findStudentById(int id);



    <select id="findStudentById" resultType="Student">
        select * from  student_tb where id = #{id}
    </select>

3.测试
    @Test //测试方法必须时 public void
    public void findAllScoreWithStudentByLazyTest(){

       List<Score> scoreList =  scoreDao.findAllScoreWithStudentByLazy();

       for (Score score:scoreList){

           // 打印对象没有触发懒加载是因为再setting 已经关闭
           System.out.println("score:"+score);

           // 获取student 相关信息 触发懒加载
           System.out.println("student:"+score.getStudent());
       }
    }

局部控制懒加载

   fetchType="lazy"  默认情况就是懒加载 因为你开启了全局懒加载
        eager 立即加载  如果配置为 eager 则会覆盖全局的开启的懒加载功能

2.mybatis的缓存

1缓存

暂时的存放常用小批量数据

特点:换窜数据不可靠(可能会丢失),存放热点数据(经常使用的数据)

优点:缓存大部分存在内存中,查询速度快

mybatis缓存

在这里插入图片描述

一级缓存:基于sqlSession,

二级缓存基于namespace,同一个namespace下所有数据可以共享

一个mapper xml 用自己的namespace,另外也可以多个mapper(dao接口)共享同一个二级缓存namespace

一级缓存

一级缓存:基于sqlSession,

前sqlSession 发生 修改,增加,删除 动作,就会把当前缓存的所有 数据清空

 @Test
    public void firstLevelCacheTest(){
        //查询所有时 可以缓存数据,但是一旦发生增加 或者删除 修改 就要清空
        studentDao.findAllStudentWithScoreLazy();


        // 查询第一次  有执行sqlselect * from student_tb where id = ?
        Student student1 =    studentDao.findStudentById(4);
        System.out.println("student1:"+student1);

        // 查询第二次  没有执行sql 没有去数据库查数据,从一级缓存sqlsession 获得数据
        Student student2 =    studentDao.findStudentById(4);
        System.out.println("student2:"+student2);

        student2.setName("志恒哥1");
        int num = studentDao.updateStudent(student2);
        System.out.println("num:"+num);

        // 再次查询数据 需要去数据库查数据 为什么?
        // 应为 当前sqlSession 发生 修改,增加,删除 动作,就会把当前缓存的所有 数据清空
        Student student3 =    studentDao.findStudentById(4);
        System.out.println("student3:"+student3);


        studentDao.findAllStudentWithScoreLazy();

    }


二级缓存

在同一namespace下,共享一块缓存空间,如果多个mapper (dao.xml)共享同一namesapce 则也共享一块缓存

二级缓存是跨sqlsession,多个sqlsession可以去二级缓存获取数据

sqlsession 获取数据先去二级缓存获取,如果有得到数据,并写入自己的一级缓存

二级缓存:只要发生增删改,就会将同一命名空间(namespace)下的缓存块清空

使用二级缓存的实体类必须实现序列化,否则报错

实现
1.开启二级缓存
  <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>

2.在mapper的命名空间下配置缓存
    <!--配置缓存
        1.开启  <cache></cache>
        2.配置参数  flushInterval="10000" 配置缓存刷新时间 清空
                     eviction="LRU" 最少使用的先删除  就是使用 LruCache 类实现
                     size="1000"  缓存最多 1000 条数据 1000 sql
                     readOnly="true" 只读不可修改 只读性能差,但是安全 获取的拷贝   可以修改 获取的缓存对象就是直接的应用
                     blocking="false" 配置是否阻塞
                     type 用来配自定义二级缓存  
    -->
    <cache flushInterval="10000" eviction="LRU" size="1000" readOnly="false" blocking="false" ></cache>


3.使用
    <!--
        useCache="true" 使用缓存 一般不需要配置 默认就开启
        
    -->
    <select id="findStudentById" resultType="Student" useCache="true" >
        select * from  student_tb where id = #{id}
    </select>


4.测试
    @Test  // 二级缓存
    public void secondLevelCacheTest(){

        // 查询第一次  有执行sqlselect * from student_tb where id = ?
        Student student1 =    studentDao.findStudentById(4);
        System.out.println("student1:"+student1);

        // 查询第二次  没有执行sql 没有去数据库查数据,从一级缓存sqlsession 获得数据
        Student student2 =    studentDao.findStudentById(4);
        System.out.println("student2:"+student2);

        // 只有sqlSession 调用close(),commit() 方法 才会将数据提交到二级换存,其他的sqlSession才能拿到
//        sqlSession.close();
        sqlSession.commit();

        // studentDao2   studentDao 来自于不同的sqlSession
        studentDao2 = sqlSessionFactory.openSession(true).getMapper(StudentDao.class);

        Student student3 = studentDao2.findStudentById(4);
        System.out.println("student3:"+student3);



    }

Mybatis使用一级缓存二级缓存时的几种情况(串数据的情况及解决办法)

情景一:从java1中查sid ,先去二级缓存找,再去一级缓存找,都没有再去数据库找,

​ 从数据库中取出来,存放在二级缓存,在存放在一级缓存,在返回给java。

​ (现在二级缓存中有java1的数据,一级缓存中也存有java1的数据)

​ 当java2查询的时候,从二级查询中取出id,没错误。

情景二:在java2中更改(增删改),再在Java2中查询,数据从Java2,二级缓存一级缓存没 找到再去MySQL中查出,传回二级缓存~一级缓存,这时候java1在查,查的是二级 缓存中,Java2更改过的数据,不会造成误差,没错误。

情景三:在java2中更改(增删改),再在Java1中查询,这时候java1查询id,查的是二级缓存 中没有更改的数据,但是id被Java2更改过了,java1取得是没有更改的id,会造成误 差

串数据的解决办法

1、不用缓存,把缓存关了再用

2、只用二级缓存,不用一级缓存

在这里插入图片描述

3.注解

开启二级缓存

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

多参数方法的参数的使用 @Param

    // 当mybatis 方法参数为多个参数 可以使用 以下几种方式
    // 1.传对象 传map
    // 2. 使用 arg0 arg1 或者 param1 param2
    // 3. 先 将参数声明,再使用  @Param("name") String name,@Param("sex") String sex
    
//    @Select("select * from student_tb where name like #{arg0} and sex = #{arg1}")
//    @Select("select * from student_tb where name like #{param1} and sex = #{param2}")
    @Select("select * from student_tb where name like #{name} and sex = #{sex}")
    List<Student> findStudentByNameAndSex(@Param("name") String name,@Param("sex") String sex);

4.pageHelper

1.引入依赖

<!--配置分页  放在最下面-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.1.4</version>
        </dependency>


2.再mybatis配置文件声明插件,

注意在 environments之前声明

    <plugins>

        <!-- 让mybatis  加载PageHelper -->
        <!-- com.github.pagehelper为PageHelper类所在包名 -->
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 使用MySQL方言的分页 -->
            <property name="helperDialect" value="mysql"/><!--如果使用mysql,这里value为mysql-->
            <property name="pageSizeZero" value="true"/>
        </plugin>

    </plugins>

3.使用

    // 以前 分页 select * from student_tb limit (pageIndex -1)* pageSize,pageSize
    // 现在   1.select * from student_tb ,其他的分页交给插件pageHelper
    @Test
    public void pageHelpTest(){

        // 开启分页  // 查询第一页 每页连个数据
        PageHelper.startPage(2,2);

        List<Student> studentList =  studentDao2.findAllStudent();

        for (Student student:studentList){
            System.out.println("student:"+student);
        }

        // 获取所有分页信息
        PageInfo<Student> pageInfo = new PageInfo<Student>(studentList);

        System.out.println("分页大小"+pageInfo.getPageSize());
        System.out.println("总页大小"+pageInfo.getPages());
        System.out.println("总条数大小"+pageInfo.getTotal());

    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值