2022尚硅谷SSM框架跟学(三)MyBatis基础三

news2024/11/20 2:29:41

2022尚硅谷SSM框架跟学 三 MyBatis基础三

      • 9.动态SQL
        • 9.1if
        • 9.2where
          • 方法一:加入恒成立的条件
          • 方法二:使用where标签
        • 9.3trim
        • 9.4choose、when、otherwise
        • 9.5foreach
          • 9.51批量添加
          • 9.52批量删除
            • 批量删除方式1
            • 批量删除方式2
            • 批量删除方式3
        • 9.6SQL片段
      • 10.MyBatis的缓存
        • 10.1MyBatis的一级缓存
        • 10.2MyBatis的二级缓存
        • 10.3二级缓存的相关配置
        • 10.4MyBatis缓存查询的顺序
        • 10.5整合第三方缓存EHCache
          • 10.5.1添加依赖
          • 10.5.2各jar包功能
          • 10.5.3创建EHCache的配置文件ehcache.xml
          • 10.5.4设置二级缓存的类型
          • 10.5.5加入logback日志
          • 10.5.6EHCache配置文件说明
      • 11.MyBatis的逆向工程
        • 11.1创建逆向工程的步骤
          • (1)添加依赖和插件
          • (2)创建MyBatis的核心配置文件
          • (3)创建逆向工程的配置文件
          • (4)执行MBG插件的generate目标
          • (5)效果
        • 11.2QBC查询
          • 测试根据主键查询
          • 测试无条件查询
          • 测试根据条件查询
          • 多条件查询
            • 多个and查询
            • 多个or查询
          • 选择性修改
          • 普通修改
      • 12分页插件
        • 12.1分页插件的使用步骤
          • (1)添加依赖
          • (2)配置分页插件
        • 12.2分页插件的使用

9.动态SQL

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了
解决 拼接SQL语句字符串时的痛点问题。
实例:多个查询条件进行查询,设置了条件的话,就一定要出现在sql中,一定要注意默认值的设置和指定。null和" "(空字符串)

新创建一个Module,这里就不再写具体步骤了,可以参考前几章
配置坐标

GroupId:com.atguigu.mybatis
Name:mybatis-dynamicSQL

配置相关文件
配置相关文件
注意配置核心配置文件mybatis-config.xml的时候要设置setting
驼峰加载

<!-- mapUnderscoreToCamelCase将下划线映射为驼峰 -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 延迟加载由2个参数决定 lazyLoadingEnabled设置true
                                  aggressiveLazyLoading设置false
         -->
        <!-- 开启延迟加载(懒加载) -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--aggressiveLazyLoading 设置false按需加载 -->
        <!--aggressiveLazyLoading 设置true全部加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

配置pojo的实体类Emp

package com.atguigu.mybatis.pojo;

/**
 * @ClassName: Emp
 * @Description:
 * @Author: wty
 * @Date: 2023/1/7
 */

public class Emp {
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    public Emp() {
    }

    public Emp(Integer empId, String empName, Integer age, String gender) {
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }

    public Integer getEmpId() {
        return empId;
    }

    public void setEmpId(Integer empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

9.1if

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行

在DynamicSQLMapper.java中添加方法

 /**
     * @param
     * @return java.util.List<com.atguigu.mybatis.pojo.Emp>
     * @description //根据条件查询员工信息
     * @param: emp
     * @date 2023/1/7 12:03
     * @author wty
     **/
    List<Emp> getEmpByCondition(Emp emp);

在DynamicSQLMapper.xml中添加sql

    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        where
        <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
        <if test="empName != null and empName != '' ">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </select>

创建测试类com.atguigu.mybatis.test.DynamicMapperTest,增加方法

    @Test
    public void getEmpByConditionTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        Emp emp = new Emp(1, "张三", 20, "男");

        List<Emp> list = mapper.getEmpByCondition(emp);

        list.forEach(System.out::println);

        sqlSession.close();
    }

查询结果
查询结果

9.2where

这里如果把where后面的条件empName置为空,那么再用测试类查询,就是错误的。
报错
同理,如果我们继续蹬鼻子上脸,把后面age和gender都置为空,那么就剩下一个select * from t_emp where的空壳
继续报错
如何解决这些问题呢,我们来看下,有如下方法

方法一:加入恒成立的条件

在DynamicSQLMapper.xml中加入恒成立的条件

    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        where 1 = 1
        <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
        <if test="empName != null and empName != '' ">
            and emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </select>

加入恒成立的条件
继续查询上面那个都是空字段的情况,看结果不报错,查询正确
查询结果

方法二:使用where标签

修改DynamicSQLMapper.xml中的sql子句变为
修改where标签

<!-- 动态sql拼接 方法二:用where标签 -->
    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        <where>
            <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </where>
    </select>

直接用测试类查询
查询结果
验证了结论:
若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字。

那我们修改一下测试类DynamicMapperTest.java的条件

 @Test
    public void getEmpByConditionTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        Emp emp = new Emp(1, "", 20, "");

        List<Emp> list = mapper.getEmpByCondition(emp);

        list.forEach(System.out::println);

        sqlSession.close();
    }

更改赋值条件
查询结果:
查询结果
验证了结论:
若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉。

where和if一般结合使用:
a>若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
b>若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉
注意:where标签不能去掉条件最后多余的and

举个例子:如果and放在条件后还可以吗

<!-- trim标签 -->
    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        <where>
            <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </where>
    </select>

将and放在后面
更改一下测试类查看结果

@Test
    public void getEmpByConditionTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        Emp emp = new Emp(1, "张三", 20, "");

        List<Emp> list = mapper.getEmpByCondition(emp);

        list.forEach(System.out::println);

        sqlSession.close();
    }

查看结果:发现报错
查看结果
这种情况我们就可以用以下的trim标签来解决

9.3trim

trim用于去掉或添加标签中的内容
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容

修改DynamicSQLMapper.xml
修改

    <!-- trim标签 -->
    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        <!-- trim的标签有4个
             prefix prefixOverrides suffix suffixOverrides
             prefix在内容前面加上指定内容
             prefixOverrides在内容前面去掉指定内容
             suffix在内容后面加上指定内容
             suffixOverrides在内容后面去掉指定内容
         -->
        <trim prefix="where" suffixOverrides="and">
            <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName} and
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </trim>
    </select>

运行测试类查看结果
查看测试结果
并且测试一下,条件为空,也可以自动去掉where
自动去掉了where
测试一下,where条件为空,只填充and
填充and

9.4choose、when、otherwise

choose、when、 otherwise相当于if…、else if…、else

在DynamicSQLMapper.java中添加方法

/**
     * @param
     * @return java.util.List<com.atguigu.mybatis.pojo.Emp>
     * @description //使用choose查询员工信息
     * @param: emp
     * @date 2023/1/7 13:43
     * @author wty
     **/
    List<Emp> getEmpByChoose(Emp emp);

修改DynamicSQLMapper.xml

 <!-- choose、when、 otherwise相当于if... 、else if.. 、else -->
    <!-- List<Emp> getEmpByChoose(Emp emp); -->
    <select id="getEmpByChoose" resultType="Emp">
        select *
        from t_emp
        <where>
            <choose>
                <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
                <when test="empName != null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="gender != null and gender != ''">
                    gender = #{gender}
                </when>
                <otherwise>
                    1 = 1
                </otherwise>
            </choose>
        </where>
    </select>

在测试类DynamicMapperTest.java中添加方法

@Test
    public void getEmpByChooseTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        Emp emp = new Emp(1, "", null, "");

        List<Emp> list = mapper.getEmpByChoose(emp);

        list.forEach(System.out::println);

        sqlSession.close();
    }

查看结果
查询结果
要注意,choose,when,otherwise都是选择条件,三个条件一起用,只是会选择第一个进行,剩下的条件就不会跑了,所以不用写and条件。例如:
多个选择
可以看出多个选择条件都可以成立,但是第一个执行后,就不会再跑其它的了。

9.5foreach

比较重要的标签,用于批量添加和批量删除。

9.51批量添加

在DynamicSQLMapper.java中添加方法

 /**
     * @param
     * @return int
     * @description //员工的批量添加
     * @param: emps
     * @date 2023/1/7 14:03
     * @author wty
     **/
    int insertMoreEmp(@Param("emps") List<Emp> emp);

修改DynamicSQLMapper.xml

<!-- int insertMoreEmp(@Param("emps") List<Emp> emp);  -->
    <insert id="insertMoreEmp" useGeneratedKeys="true" keyProperty="empId">
        insert into t_emp
        values
        <!--foreach标签
             collection属性:放入Mapper接口Param注解中定义的变量即可
             item 可以理解为一行数据,即一个对象
             separator 表示分隔符,每一次循环后以,分割,最后一次没有
        -->
        <foreach collection="emps" item="emp" separator=",">
            <!-- 这里用emp.empName是因为返回值类型是List,而emp才是每一行数据的实体对象 -->
            (null, #{emp.empName}, #{emp.age}, #{emp.gender}, null)
        </foreach>
    </insert>

在测试类DynamicMapperTest.java中添加方法

 @Test
    public void insertMoreEmpTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        List<Emp> list = new ArrayList<>();
        list.add(new Emp(null, "周七", 29, "男"));
        list.add(new Emp(null, "朱八", 22, "男"));
        list.add(new Emp(null, "李九", 23, "女"));

        int i = mapper.insertMoreEmp(list);

        System.out.println("插入:" + i + "条数据");

        sqlSession.close();
    }

插入结果
插入数据
插入结果

9.52批量删除
批量删除方式1

在DynamicSQLMapper.java中添加方法

    /**
     * @param
     * @return int
     * @description //批量删除
     * @param: empIds
     * @date 2023/1/7 14:39
     * @author wty
     **/
    int deleteMoreEmp(@Param("empIds") Integer[] empIds);

修改DynamicSQLMapper.xml

    <!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
    <delete id="deleteMoreEmp">
        delete
        from t_emp
        where emp_id in
        (
        <foreach collection="empIds" item="empId" separator=",">
            #{empId}
        </foreach>
        )
    </delete>

在测试类DynamicMapperTest.java中添加方法

  @Test
    public void deleteMoreEmp() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);


        Integer empIds[] = {5, 6, 7};

        int i = mapper.deleteMoreEmp(empIds);

        System.out.println("删除:" + i + "条数据");

        sqlSession.close();
    }

查看删除结果:
删除结果
看到3条已经删除了
3条删除了

批量删除方式2

用另一种批量删除的方式,更改DynamicSQLMapper.xml

    <!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
    <delete id="deleteMoreEmp">
        delete
        from t_emp
        where emp_id in
        <!-- open以什么开始 close以什么结束 -->
        <foreach collection="empIds" item="empId" separator="," open="(" close=")">
            #{empId}
        </foreach>
    </delete>

先重新执行一下批量插入的方法。
插入数据

再删除一下,看一下这种方式是否能删除成功。
删除3条数据
删除结果
删除结果

批量删除方式3

修改DynamicSQLMapper.xml

<!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
    <delete id="deleteMoreEmp">
        delete
        from t_emp
        where
        <foreach collection="empIds" item="empId" separator="or">
            emp_id = #{empId}
        </foreach>
    </delete>

执行测试类删除方法前,也先执行一下批量插入的方法
插入

执行测试类DynamicMapperTest.java

 @Test
    public void deleteMoreEmp() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);


        Integer empIds[] = {11, 12, 13};

        int i = mapper.deleteMoreEmp(empIds);

        System.out.println("删除:" + i + "条数据");

        sqlSession.close();
    }

执行结果
结果1
成功删除
总结

foreach标签的属性
collection:设置要循环的数组或者集合
item:用一个字符串表示数组或者集合中的每一个数据
separator:设置每次循环的数据之间的分隔符
open:循环的所有内容以什么开始
close:循环的所有内容以什么结束

9.6SQL片段

sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入

在DynamicSQLMapper.java中添加方法

    /**
     * @param
     * @return java.util.List<com.atguigu.mybatis.pojo.Emp>
     * @description //查询所有用户
     * @date 2023/1/7 15:10
     * @author wty
     **/
    List<Emp> getAllEmp();

修改DynamicSQLMapper.xml

<sql id="empColumns">
        emp_id,emp_name,age,gender,dept_id
    </sql>

    <!-- List<Emp> getAllEmp(); -->
    <select id="getAllEmp" resultType="Emp">
        select
        <!-- 使用的时候用 include  refid属性放sql中的id -->
        <include refid="empColumns"></include>
        from t_emp
    </select>

在测试类DynamicMapperTest.java中添加方法

 @Test
    public void getAllEmpTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        List<Emp> list = mapper.getAllEmp();

        list.forEach(System.out::println);

        sqlSession.close();
    }

查询结果
查询结果
可以看到sql中的字段会在查询的时候调用

10.MyBatis的缓存

10.1MyBatis的一级缓存

MyBatis的一级缓存是默认开启的,创建一个工程就可以直接使用。
创建新的Module

GroupId:com.atguigu.mybatis
Name:mybatis-cache

配置相关信息和参数见前面几章,这里就不赘述了,创建完后工程是这样的:
Module
在CacheMapper.java中添加方法

    /**
     * @param
     * @return com.atguigu.mybatis.pojo.Emp
     * @description //根据员工Id查询员工信息
     * @param: empId
     * @date 2023/1/7 16:44
     * @author wty
     **/
    Emp getEmpById(@Param("empId") Integer empId);

在CacheMapper.xml中新加语句

<sql id="empColumns">
        emp_id
        ,emp_name,age,gender,dept_id
    </sql>

    <!-- Emp getEmpById(@Param("empId") Integer empId); -->
    <select id="getEmpById" resultType="Emp">
        select
        <include refid="empColumns"></include>
        from t_emp
        where emp_id = #{empId}
    </select>

在测试类CacheMapperTest.java中添加方法测试

  @Test
    public void getEmpByIdTest() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);

        Emp emp1 = mapper.getEmpById(4);
        System.out.println(emp1);

        Emp emp2 = mapper.getEmpById(4);
        System.out.println(emp2);

        sqlSession.close();
    }

查询结果如下:
查询结果

一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。

既然一级缓存是SqlSession级别的,那我们来看看是不是这样的。
修改CacheMapperTest.java

@Test
    public void getEmpByIdTest() {
        SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);

        Emp emp1 = mapper1.getEmpById(4);
        System.out.println(emp1);

        Emp emp2 = mapper1.getEmpById(4);
        System.out.println(emp2);

        sqlSession1.close();

        SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();

        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);

        Emp emp3 = mapper2.getEmpById(4);

        System.out.println(emp3);

        sqlSession2.close();
    }

查看结果
结果
可以看到同一个Sqlsession的确再查询第二次时,会使用缓存,而不同的SqlSession查询相同sql的时候,会重新查询,这样就验证了一级缓存是SqlSession级别的。

使一级缓存失效的四种情况:

  1. 不同的SqlSession对应不同的一级缓存。
  2. 同一个SqlSession但是查询条件不同。
  3. 同一个SqlSession两次查询期间执行了任何一次增删改操作。
  4. 同一个SqlSession两次查询期间手动清空了缓存。

针对情况(3)举个例子来理解
在CacheMapper.java中添加方法

 /**
     * @param
     * @return int
     * @description //添加员工信息
     * @param: emp
     * @date 2023/1/7 17:08
     * @author wty
     **/
    int insertEmp(Emp emp);

在CacheMapper.xml中新加语句

 <!-- int insertEmp(Emp emp); -->
    <insert id="insertEmp">
        insert into t_emp
        values (null, #{empName}, #{age}, #{gender}, null)
    </insert>

在测试类CacheMapperTest.java中修改getEmpByIdTest方法测试

 @Test
    public void getEmpByIdTest() {
        SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);

        Emp emp1 = mapper1.getEmpById(4);
        System.out.println(emp1);

        // 如果执行了任意的增删改,则会清空缓存,重新查询
        Emp emp = new Emp(null, "周七", 29, "男");
        int i = mapper1.insertEmp(emp);

        System.out.println("插入了" + i + "条");

        Emp emp2 = mapper1.getEmpById(4);
        System.out.println(emp2);

        sqlSession1.close();
    }

在2个查询之间进行一次新增操作
测试类
查询结果
结果
结果发现增删改之后,缓存清空,会查询数据库。

针对情况(3)举个例子来理解
修改CacheMapperTest.java中的getEmpByIdTest方法

sqlSession1.clearCache(); // 清理缓存

@Test
    public void getEmpByIdTest() {
        SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);

        Emp emp1 = mapper1.getEmpById(4);
        System.out.println(emp1);

        sqlSession1.clearCache();

        Emp emp2 = mapper1.getEmpById(4);
        System.out.println(emp2);

        sqlSession1.close();
    }

查看结果
查询数据库

10.2MyBatis的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。
二级缓存开启的条件:
< a >.在核心配置文件中,设置全局配置属性cacheEnabled=“true” ,该属性,默认为true,不需要设置。

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

< b >.在mapper映射文件中设置标签

<cache/>

< c >.二级缓存必须在SqlSession关闭或提交之后有效

sqlSession1.close();

< d >.查询的数据所转换的实体类类型必须实现序列化的接口

public class Emp implements Serializable {}

学习了上面的知识点之后,我们一起来看下二级缓存。
在核心配置文件中添加语句(可以省略)
核心配置文件

        <setting name="cacheEnabled" value="true"/>

在CacheMapper.xml中新加语句
添加缓存开启语句
Mapper配置文件
在测试类CacheMapperTest.java中添加方法测试

    @Test
    public void testCache() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

    }

查询结果
数据库
看到查询结果是去数据库查询了2次,说明二级缓存还没有生效,原来是sqlSession我们还没有关闭,那我们关闭一下。

@Test
    public void testCache() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

        sqlSession1.close();
        sqlSession2.close();
    }

执行测试类,发现报错。
报错

org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: com.atguigu.mybatis.pojo.Emp

自定义类Emp没有实现序列化,那我们将Emp进行实现
序列化

快捷产生序列化的版本号
序列化

package com.atguigu.mybatis.pojo;

import java.io.Serializable;

/**
 * @ClassName: Emp
 * @Description:
 * @Author: wty
 * @Date: 2023/1/7
 */

public class Emp implements Serializable {
    private static final long serialVersionUID = -936807110083368555L;
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    public Emp() {
    }

    public Emp(Integer empId, String empName, Integer age, String gender) {
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }

    public Integer getEmpId() {
        return empId;
    }

    public void setEmpId(Integer empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

这里更改测试类中的方法

 @Test
    public void testCache() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);
        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

        sqlSession2.close();
    }

查看运行结果
运行结果

使二级缓存失效的情况: 两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

这样便实现了MyBatis的二级缓存。
而如果想让二级缓存失效我们尝试用增删改放在两次查询的中间
修改CacheMapperTest.java

 @Test
    public void testCache() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);

        // 二级缓存失效
        Emp emp = new Emp(null, "朱八", 26, "男");

        int i = mapper1.insertEmp(emp);
        System.out.println("插入了" + i + "条");
        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

        sqlSession2.close();
    }

查询结果
查询结果
这第二次查询还是查询了数据库,说明增删改,清空了二级缓存,需要重新查询数据库。

10.3二级缓存的相关配置

在mapper配置文件中添加的cache标签可以设置一些属性:
①eviction属性:缓存回收策略,默认的是 LRU。
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
②flushInterval属性:刷新间隔,单位毫秒。
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新 ③size属性:引用数目,正整数。
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
④readOnly属性:只读, true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

10.4MyBatis缓存查询的顺序

从大范围到小范围即(sqlSessionFactory 二级缓存→ SqlSession一级缓存)

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存

10.5整合第三方缓存EHCache

10.5.1添加依赖

在pom.xml中添加依赖

<!-- Mybatis EHCache整合包 -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.2.1</version>
        </dependency>
        <!-- slf4j日志门面的一个具体实现 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

简单讲述
简单讲述

10.5.2各jar包功能
jar包名称作用
mybatis-ehcacheMybatis和EHCache的整合包
ehcacheEHCache核心包
slf4j-apiSLF4J日志门面包
logback-classic支持SLF4J门面接口的一个具体实现
10.5.3创建EHCache的配置文件ehcache.xml

创建配置文件

<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!-- 磁盘保存路径 -->
    <diskStore path="F:\javawebwork\ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>
10.5.4设置二级缓存的类型

在CacheMapper.xml中设置
二级缓存

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
10.5.5加入logback日志

存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。 创建logback的配置文件logback.xml

添加包名

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 指定日志输出的位置 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日志输出的格式 -->
            <!-- 按照顺序分别是: 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行
            -->
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger]
                [%msg]%n
            </pattern>
        </encoder>
    </appender>
    <!-- 设置全局日志级别。日志级别按顺序分别是: DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="DEBUG">
        <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
        <appender-ref ref="STDOUT"/>
    </root>
    <!-- 根据特殊需求指定局部日志级别 -->
    <logger name="com.atguigu.mybatis.mapper" level="DEBUG"/>
</configuration>

修改CacheMapperTest.java

 @Test
    public void testCache() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);

        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

        sqlSession2.close();
    }

查询结果
查询结果
缓存位置
缓存位置

10.5.6EHCache配置文件说明
属性名是否必须作用
maxElementsInMemory在内存中缓存的element的最大数目
maxElementsOnDisk在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断
overflowToDisk设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
timeToIdleSeconds当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMBDiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
diskPersistent在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
diskExpiryThreadIntervalSeconds磁盘缓存的清理线程运行间隔,默认是120秒。每隔120s, 相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU (最近最少使用),可选的有LFU (最不常使用)和FIFO (先进先出)

11.MyBatis的逆向工程

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
Java实体类
Mapper接口
Mapper映射文件
注意:逆向工程只能针对单表操作,多表不支持

11.1创建逆向工程的步骤

新创建一个Module

GroupId:com.atguigu.mybatis
Name:mybatis-mbg

创建一个Module

(1)添加依赖和插件

在pom.xml中添加依赖
这里要注意mysql的版本,配置成和自己安装的一致即可。

<!-- 依赖MyBatis核心包 -->
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- log4j日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.20</version>
        </dependency>
    </dependencies>
    <!-- 控制Maven在构建过程中相关配置 -->
    <build>
        <!-- 构建过程中用到的插件 -->
        <plugins>
            <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.0</version>
                <!-- 插件的依赖 -->
                <dependencies>
                    <!-- 逆向工程的核心依赖 -->
                    <dependency>
                        <groupId>org.mybatis.generator</groupId>
                        <artifactId>mybatis-generator-core</artifactId>
                        <version>1.3.2</version>
                    </dependency>
                    <!-- MySQL驱动 -->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.20</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

添加打包方式
设置打包方式

<packaging>jar</packaging>
(2)创建MyBatis的核心配置文件

创建核心配置文件

(3)创建逆向工程的配置文件

文件名必须是:generatorConfig.xml

逆向工程
这里创建的是MyBatis3Simple: 清新简洁版

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
    targetRuntime: 执行生成的逆向工程的版本
    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
    MyBatis3: 生成带条件的CRUD(奢华尊享版)
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm?"
                        userId="root"
                        password="hsp">
        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.atguigu.mybatis.pojo"
                            targetProject=".\src\main\java">
            <!-- enableSubPackages 设置成true表示可以使用子包 -->
            <property name="enableSubPackages" value="true"/>
            <!-- 把数据库字段的前后空格去掉生成实体类的属性  -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"
                         targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>
(4)执行MBG插件的generate目标

配置完依赖多了插件
插件
双击插件
双击
最后创建成功即可
创建成功

(5)效果

创建成功
看Mapper接口中有5个方法

package com.atguigu.mybatis.mapper;

import com.atguigu.mybatis.pojo.Emp;
import java.util.List;

public interface EmpMapper {
    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    int deleteByPrimaryKey(Integer empId);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    int insert(Emp record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    Emp selectByPrimaryKey(Integer empId);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    List<Emp> selectAll();

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    int updateByPrimaryKey(Emp record);
}

下面创建一下MyBatis3: 奢华尊享版
更改generatorConfig.xml

    <context id="DB2Tables" targetRuntime="MyBatis3">

创建尊享版
删除逆向工程创建的包和类
删除
重新运行插件
重新运行插件
运行结果,查看
运行结果

11.2QBC查询

创建MBGTest.java测试类
创建测试类
在MBGTest.java中添加方法

测试根据主键查询
 @Test
    public void testMBG() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        Emp emp = mapper.selectByPrimaryKey(1);

        System.out.println(emp);

        sqlSession.close();
    }

执行MBGTest.java结果
在这里插入图片描述
给Emp添加toString()方法
toString()方法
执行结果
执行结果

在MBGTest.java中添加方法——

测试无条件查询
@Test
    public void testMBG1() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> list = mapper.selectByExample(null);

        list.forEach(System.out::println);

        sqlSession.close();
    }

条件为null的时候,相当于查询全部
查询结果

测试根据条件查询

这里需要创建EmpExample对象
方法
在MBGTest.java中添加方法
根据条件查询:一个叫张三的员工

 @Test
    public void testMBG2() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据条件查询:一个叫张三的员工
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三");

        List<Emp> list = mapper.selectByExample(empExample);

        list.forEach(System.out::println);

        sqlSession.close();
    }

查询结果
查询结果

多条件查询
多个and查询

如果我们在员工是张三的基础上,加入查询条件:年龄大于等于20岁,那我们只需要继续在后面拼接即可。
查询

 @Test
    public void testMBG2() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据条件查询:一个叫张三的员工
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);

        List<Emp> list = mapper.selectByExample(empExample);

        list.forEach(System.out::println);

        sqlSession.close();
    }

查询结果
多条件

多个or查询

那如果掺杂了or怎么办呢,比如我们需要查询叫张三,年龄大于等于20岁,或者性别是女的员工
修改MBGTest.java类的方法
修改方法

@Test
    public void testMBG2() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据条件查询:一个叫张三的员工
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
        empExample.or().andGenderEqualTo("女");

        List<Emp> list = mapper.selectByExample(empExample);

        list.forEach(System.out::println);

        sqlSession.close();
    }

查询结果
查询结果

选择性修改

Emp.java添加有参构造
有参构造
在MBGTest.java中添加方法

    @Test
    public void testMBG4() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据选择性修改:
        Emp emp = new Emp(14, "小丽", null, "女");
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);

        int i = mapper.updateByPrimaryKeySelective(emp);

        System.out.println("更新了" + i + "条数据");

        sqlSession.close();
    }

因为是选择性修改,null的值不会替换修改
null没有修改

普通修改

在MBGTest.java中添加方法

@Test
    public void testMBG3() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据主键修改:
        Emp emp = new Emp(14, "小美", 26, "女");
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);

        int i = mapper.updateByPrimaryKey(emp);

        System.out.println("更新了" + i + "条数据");

        sqlSession.close();
    }

修改结果
修改结果
修改结果

12分页插件

limit index,pageSize
pageSize:每页显示的条数
pageNum:当前页的页码
index:当前页的起始索引,index=(pageNum-1)*pageSize
count:总记录数
totalPage:总页数
totalPage = count / pageSize;
if(count % pageSize != 0){
totalPage += 1;
}
pageSize=4,pageNum=1,index=0 limit 0,4
pageSize=4,pageNum=3,index=8 limit 8,4
pageSize=4,pageNum=6,index=20 limit 20,4
导航分页:
首页 上一页 2 3 4 5 6 下一页 末页

12.1分页插件的使用步骤

(1)添加依赖

在pom.xml中添加依赖

<!-- 分页插件 -->
                    <dependency>
                        <groupId>com.github.pagehelper</groupId>
                        <artifactId>pagehelper</artifactId>
                        <version>5.2.0</version>
                    </dependency>

添加依赖

(2)配置分页插件

在MyBatis的核心配置文件中配置插件
在mybatis-config.xml中配置
配置拦截器

    <plugins>
        <!--设置分页插件-->
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

这里的全类名如果不太好找可以使用IDEA自带的全类名搜索:快捷键Ctrl+Shift+a
在搜索栏点选class然后搜索PageInterceptor
搜索
拷贝全类名即可
拷贝全类名
新建测试类PageTest.java来测试分页功能
测试类
去sqlyog中将表t_emp截断,重新插入一些数据,30条

12.2分页插件的使用

< a >在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能。

pageNum:当前页的页码
pageSize:每页显示的条数

在测试类PagTest.java中添加方法

 @Test
    public void testPage() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 分页查询
        // 开启分页功能
        PageHelper.startPage(1, 4);

        List<Emp> list = mapper.selectByExample(null);
        list.forEach(System.out::println);

        sqlSession.close();
    }

查询结果:
查询结果
分析一下查询结果:
打印一下page值

    @Test
    public void testPage() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 分页查询
        // list前开启分页功能
        Page<Object> page = PageHelper.startPage(1, 4);

        List<Emp> list = mapper.selectByExample(null);
        list.forEach(System.out::println);
        System.out.println(page);

        sqlSession.close();
    }

输出结果:
输出结果
注意Page是继承自ArrayList
在这里插入图片描述
这里可以处结论可以自定义接口返回值Page获取查询结果
自定义接口返回值

< b >在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据。

list:分页之后的数据
navigatePages:导航分页的页码数

修改PageTest.java中的方法

 /**
     * PageInfo{
     * pageNum=4, pageSize=4, size=4, 当前是第4页,此页中有4条数据
     * startRow=13, endRow=16,  当前页的数据是从第13行数据到16条数据
     * total=30, pages=8, 所有页一共30条数据,一共8页。符合30/4 = 7……2 则总页数是7 + 1 = 8
     * list=Page{count=true, pageNum=4, pageSize=4, startRow=12, endRow=16, total=30, pages=8, reasonable=false, pageSizeZero=false}[Emp{empId=13, empName='a', age=null, gender='null', deptId=null}, Emp{empId=14, empName='a', age=null, gender='null', deptId=null}, Emp{empId=15, empName='a', age=null, gender='null', deptId=null}, Emp{empId=16, empName='a', age=null, gender='null', deptId=null}],
     * prePage=3, nextPage=5, 当前页是第4页,所以上一页的页码是3,后一页的页码是5
     * isFirstPage=false, isLastPage=false, 是否是第一页,是否是最后一夜
     * hasPreviousPage=true, hasNextPage=true, 是否有上一页,是否有下一页
     * navigatePages=4, 当前页
     * navigateFirstPage=2,导航分页的初始页
     * navigateLastPage=5, 导航分页的最终页
     * navigatepageNums=[2, 3, 4, 5]}导航分页的页码
     */
    @Test
    public void testPage1() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 分页查询
        Page<Object> page = PageHelper.startPage(4, 4);

        List<Emp> list = mapper.selectByExample(null);

        // list后开启分页功能
        // navigatePages:导航分页的个数,比如设置4,导航分页就是2,3,4,5
        // 比如设置5,导航分页是2,3,4,5,6
        PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);

        list.forEach(System.out::println);
        System.out.println(pageInfo);

        sqlSession.close();
    }

查询结果:
查询结果
< c >分页相关数据

PageInfo{
pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,
list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,
pages=8, reasonable=false, pageSizeZero=false},
prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true,
hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8,
navigatepageNums=[4, 5, 6, 7, 8]
}
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/148788.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS基础(一)——认识JS及其基础语法

网页的三个组成部分 HTML&#xff1a;用于控制网页的内容CSS&#xff1a;用于控制网页的样式JavaScript&#xff1a;用于控制网页的行为 网页的行为指用户与浏览器的行为交互、浏览器与浏览器与服务器的数据交互。 ECMAScriptS&#xff08;ES&#xff09; ECMAScriptS是Java…

OpenCV入门

OpenCV入门图像金字塔高斯金字塔(cv2.pyrUp、cv.pyrDown)拉普拉斯金字塔边缘检测图像轮廓 (cv2.findContours)轮廓特征&#xff08;cv2.contourArea、cv2.arcLength&#xff09;轮廓近似(cv2.approxPolyDP)边界矩形、外接圆(cv2.boundingRect、cv2.minEnclosingCircle)模板匹配…

C库函数:time.h

time.h C 标准库 – <time.h> | 菜鸟教程 (runoob.com) 库变量 下面是头文件 time.h 中定义的变量类型&#xff1a; 序号变量 & 描述1size_t 是无符号整数类型&#xff0c;它是 sizeof 关键字的结果。2clock_t 这是一个适合存储处理器时间的类型。3time_t is 这是一…

C库函数:math.h

math.h C 标准库 – <math.h> | 菜鸟教程 (runoob.com) 16double pow(double x, double y) 返回 x 的 y 次幂。17double sqrt(double x) 返回 x 的平方根。18double ceil(double x) 返回大于或等于 x 的最小的整数值。19double fabs(double x) 返回 x 的绝对值。20doubl…

矩阵分析:QR分解

Householder变换 Householder变换是一种简洁而有意思的线性变换&#xff0c;也可称为镜面反射变换&#xff0c;Householder变换矩阵为HI−wTwHI-w^TwHI−wTw 考虑向量α\alphaα和一个单位向量w:wTw1w:w^{T}w1w:wTw1 α\alphaα在www 方向上的分量是 αw//(wTα)wwwTα\alpha _…

Python快速制作自动填写脚本:100%准确率

嗨害大家好鸭&#xff01;我是小熊猫~ 环境使用 Python 3.8Pycharm 模块使用 import requests —> 数据请求模块 pip install requestsimport parsel —> 数据解析模块 pip install parselfrom selenium import webdriver —> 自动测试模块 pip install selenium3.…

#H. Linear Approximation

Description给你一个数列A&#xff0c;希望你找出一个数字B。使得下面这个式子的值最小Abs(A1-(B1))Abs(A2-(B2))Abs(A3-(B3))..........Abs(An-(Bn))FormatInput第一行给出输入n第二行给出数列A,数字的值在[1,1e9]N<2e5Output如题Samples输入数据 152 2 3 5 5输出数据 12思…

WQS二分

本博客以一种较为少见的方式来解释WQS二分。 题目 首先&#xff0c;WQS二分用于解决什么问题&#xff1f; 我们先看一个伞兵题目&#xff1a; 有一个 nnn 个数的数组 aaa。 求在 aaa 中恰好选择 mmm 个数的情况下&#xff0c;选择的数的和的最大值。 你现在看到了这个题目&a…

Jenkins基于Blue Ocean UI构建流水线

目录 一、Blue Ocean 简介 二、Blue Ocean 安装 2.1 安装 Blue Ocean 插件 2.2 安装 Blue Ocean 版本的 Jenkins 3. 构建流水线 4. 创建流水线 5. 选择代码仓库 6. 连接Git仓库 7. 创建流水线 详细信息可以参考官网&#xff1a;Blue Ocean 入门 一、Blue Ocean 简介…

牛客竞赛每日俩题 - Day13

目录 洪泛法BFS 26进制计数字符串 洪泛法BFS 红与黑__牛客网 循环接收每组用例&#xff0c;对于每组用例进行如下操作&#xff1a; 找到‘’所在的位置&#xff0c;即起始搜索的点 使用DFS搜索地板中的每块瓷砖&#xff0c;如果是黑色&#xff0c;给计数1&#xff0c;然后像…

JavaSE学习day2_01, 数据类型

1. 数据类型 1.1 Java中数据类型的分类,重点 基本数据类型 引用数据类型 1.2 基本数据类型的四类八种 整数类型&#xff1a;byte、short、int、long 浮点类型&#xff1a;float、double 字符类型&#xff1a;char 布尔类型&#xff1a;boolean,只有两个取值,true和false…

HW13 Network Compression网络压缩

文章目录一、任务描述1、介绍知识蒸馏2、介绍架构设计二、实验1、simple baselineconfigs结构设计训练2、medium baselineconfigs3、strong baselineconfigsReLu和leakyRelu知识蒸馏一、任务描述 ●网络压缩&#xff1a;使您的模型更小而不损失性能。 ●在这个任务中&#xff…

初级算法之深度搜索

目录 ​编辑 概述&#xff1a; 个人对深搜的理解&#xff1a; 深搜模板&#xff1a; 例题&#xff1a; 题目描述 输入格式 输出格式 输入输出样例 说明/提示 代码图示&#xff1a; 概述&#xff1a; 在我们刷算法的过程中肯定会想到暴力通过&#xff0c;暴力是不需要…

分类预测 | MATLAB实现超参数优化朴素贝叶斯(Naive Bayesian)多特征分类预测

分类预测 | MATLAB实现超参数优化朴素贝叶斯(Naive Bayesian)多特征分类预测 目录 分类预测 | MATLAB实现超参数优化朴素贝叶斯(Naive Bayesian)多特征分类预测分类效果基本介绍程序设计学习小结参考资料分类效果 基本介绍 MATLAB实现超参数优化朴素贝叶斯(Naive Bayesian)多特…

行为型-策略模式

策略模式简介 策略模式&#xff08;Strategy Pattern&#xff09;属于对象的行为模式。其用意是针对一组算法&#xff0c;将每一个算法封装到具有共同接口的独立的类中&#xff0c;从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。其主要目…

【Kotlin】空安全 ⑤ ( 异常处理 | 捕获并处理异常 | 抛出自定义异常 )

文章目录一、Kotlin 中的异常处理1、捕获并处理异常2、抛出自定义异常一、Kotlin 中的异常处理 在 Kotlin 程序中 , 处理异常 的方式有 : 抛出默认异常抛出自定义异常捕获并处理异常 1、捕获并处理异常 捕获异常代码示例 : 在下面的代码中 , name 变量是可空类型变量 , 其初始…

C语言入门(三)——简单函数

数学函数在数学中我们用过sin和ln这样的函数&#xff0c;例如Vin(ʌ &#xff0c;ln10等等&#xff0c;在C语言中也可以使用这些函数&#xff08;ln函数在C标准库中叫做log&#xff09;&#xff1a;在C语言中使用数字函数#include <math.h> #include <stdio.h> int…

生物化学 SY003地西泮(三大经典药物的老三)

历史 1864年 巴比妥酸 2,4,6-三羟基嘧啶, 丙二酰脲 “芭芭拉的尿酸” 巴比妥酸是一种有机化合物&#xff0c;化学式为C4H4N2O3&#xff0c;它由德国化学家阿道夫冯拜尔在研究尿酸时发现。巴比妥酸的德语名称“Barbitursure”衍生自拜尔的爱人芭芭拉&#xff08;Babara&#xf…

本周大新闻|CES 2023 AR/VR最全汇总

本周正值CES 2023举办期间&#xff0c;大新闻正好结合大会上的AR/VR新闻进行汇总。AR方面&#xff0c;The Information爆料更多苹果AR/VR头显信息&#xff1b;郭明錤表示苹果MR或再次推迟至Q3或年底&#xff1b;Mojo Vision裁员75%&#xff0c;专注Micro LED技术&#xff1b;消…

数据结构之二叉树的相关概念

今天我们来了解一下二叉树是什么。 二叉树介绍 要想明白二叉树&#xff0c;还得先了解一下树的定义。 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff…