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

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包功能

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配置文件说明

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]

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿尔法波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值