初识Mybatis(二)动态SQL、缓存和逆向工程

news2024/11/15 9:39:25

动态SQL

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。

(比如多条件查询的设置,实现判空等)

1、if

创建DynamicSQLMapper接口,DynamicSQLMapper.xml文件

 DynamicSQLMapper接口:
 List<Emp> getEmpByCondition(Emp emp);

 DynamicSQLMapper.xml中:
<select id="getEmpByCondition" resultType="Emp">
        select * from t_emp where
        <if test="empName != null and empName != ''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="empName != null and empName != ''">
            and gender = #{gender}
        </if>
    </select>

List集合作为方法的返回值,以防查出多个数据。

以上用if条件作为sql的查询判断筛选结果,但存在问题,原意是判断如果查询条件中姓名不为空(即需要查询姓名)则将姓名条件赋值,后面对年龄、性别的if语句也是做同样的判断,实现最终sql语句的拼接。

创建测试方法DynamicSQLMapperTest

public void testGetEmpByCondition(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
        Emp emp = new Emp(null, "大大", 7, "女");
        List<Emp> empByCondition = mapper.getEmpByCondition(emp);
        empByCondition.forEach(System.out::println);
    }

从赋值条件可以看出,是实现查询姓名为大大、年龄为7、性别为女的记录。如下得到对应的查询结果,我们可以知道如果只有性别做了指定,到那时其余为空,则我们将查询到男或女的所有数据。(这个实现其实就是if的逻辑,如果我们设定的条件不为空则会拼接到sql语句,进行条件查询)

但是如果第一个条件(上述代码为对empName是否赋值的判断)不成立,where后则会直接凭借下一个语句,为符合和语法(where后面不可以直接加and),一般会在where语句后加上一个恒成立条件,拼接较为完善的sql语句

<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp where 1=1
    <if test="empName != null and empName != ''">
       and emp_name = #{empName}
    </if>
    <if test="age != null and age != ''">
        and age = #{age}
    </if>
    <if test="empName != null and empName != ''">
        and gender = #{gender}
    </if>
</select>

2、where

where和if一般结合使用:

<select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
            <if test="empName != null and empName != ''">
                 emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="empName != null and empName != ''">
                and gender = #{gender}
            </if>
        </where>
    </select>


a>若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字

eg:上述条件都不满足,则会执行select * from t_emp


b>若where标签中的if条件满足,则where标签会自动添加where关键字,

eg:第一个条件满足,但前面没有where会自动添加即select * from t_emp  where emp_name = #{empName}

并将条件最前方多余的and去掉 ,eg:第一个条件不满足,后面带有and的条件满足,则自动去掉and拼接,

select * from t_emp  where age = #{age} and gender = #{gender} (后面两个都满足)
注意:where标签不能去掉条件最后多余的and(即把and放在条件后面时,age = #{age} and)

3、trim

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

<select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <trim prefix="where" suffixOverrides="and">
            <if test="empName != null and empName != ''">
                emp_name = #{empName} and
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="empName != null and empName != ''">
                gender = #{gender} and
            </if>
        </trim>

4、choose、when、otherwise

choose、when(if else...if)、otherwise(else)相当于if...else if..else

(when至少设置一个,otherwise最多设置一个)

<select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName != null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <otherwise>
                    gender = #{gender}
                </otherwise>
            </choose>
        </where>
    </select>

上述逻辑:当为empName赋值查询(即不为null或空字符串时)将emp_name = #{empName}拼接到sql语句,但是后面的内容将不再判断执行,只要有一个满足要求,后面都不会再继续判断,而当前面都不满足代码中有othwise标签,则执行该标签的内容(即都没有给empName合age赋值,则根据gender赋值查询(注意,当查询内容条件都为空时,因为在where标签下,会自动补上where,则查询语句变成select * from t_emp WHERE gender = ?,查询结果如下

a

5、foreach

1、用foreach实现批量添加

 <!--    void insertMoreEmp(@Param("emps") List<Emp> emps);-->
    <insert id="insertMoreEmp" >
        insert into t_emp values
        <foreach collection="emps" item="emp" separator=",">
            (null,#{emp.empName},#{emp.age},#{emp.gender},null)
        </foreach>
    </insert>

如果传输过来的是list集合数据,collection属性应该写list,可以采取@param注解方法,那么下次直接填写设置的参数名即可。即@param(“emps”),则collection=emps获取该list集合数据。

且item的赋值就是个参数名,可以自己取,记得插入的值不是empName,而是emp.empName(因为item在这里为emp,所以是item.empName),我们获取的是list集合,里面都是由Emp对象组成,所以要获取单个属性值,应该是对象.属性名的形式(我是这么理解的)

上面代码的相关属性如下,可以知道separator=”,“是为了实现插入多个数值并隔开的效果,values(),(),(),()(不是单纯的在插入语句后加,因为最后还有会一个逗号存在

属性:
collection:设置要循环的数组或集合
item:表示集合或数组中的每一个数据
separator:设置循环体之间的分隔符
open:设置foreach标签中的内容的开始符
close:设置foreach标签中的内容的结束符

测试代码如下,

 public void testinsertMoreEmp(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
        Emp emp = new Emp(null, "小饿", 3, "男");
        Emp emp1 = new Emp(null, "紫紫", 7, "女");
        Emp emp2 = new Emp(null, "凹凸", 4, "女");
        List<Emp> emps = Arrays.asList(emp,emp1,emp2);
        mapper.insertMoreEmp(emps);
    }

插入结果如图

(补充:mapper接口的方法中参数值为list的时候,mybatis都会把数据放在map中,以list为键,当前参数为值,如果是数组,则以array为键,当前参数为值

eg

如下为数组形式的测试方法:

public void testinsertMoreEmpArray(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
        Emp emp = new Emp(null, "小粉", 3, "女");
        Emp emp1 = new Emp(null, "小黑", 4, "女");
        Emp emp2 = new Emp(null, "三日兔", 7, "女");
        Emp[] emps = new Emp[]{emp,emp1,emp2};
        mapper.insertMoreEmpArray(emps);
    }

所以还是用注解好,直接写注解取的名字。

2、用foreach实现批量删除

 <!--void 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>

其括号可以如下替换表示

或是

(seperator=or,其实在拼接sql语句时or前后自动由空格)

如下为测试方法,删除id为10和13的记录

 public void testdeleteMoreEmp(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
        Integer[] empIds = {10, 13};
        mapper.deleteMoreEmp(empIds);
    }

SQL片段

sql标签,将常用的sql片段进行记录,用include的标签在需要时引入。

 <sql id="context">
        emp_id,emp_name,age,gender,dept_id
    </sql>
    <!--List<Emp> getEmpByCondition(Emp emp);-->
    <select id="getEmpByCondition" resultType="Emp">
        select <include refid="context"></include> from t_emp

id名自取

 MyBatis的缓存

1、MyBatis的一级缓存(默认开启)

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

使一级缓存失效的四种情况:
1) 不同的SqlSession对应不同的一级缓存
(所以如果是如下测试创建并使用了不同的SqlSession,
public void testGetEmpById(){
        SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp empById = mapper1.getEmpById(1);
        System.out.println(empById);
        Emp empById1 = mapper1.getEmpById(1);
        System.out.println(empById1);

        SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp empById2 = mapper2.getEmpById(1);
        System.out.println(empById2);
    }
则会执行两次sql语句,第一次打印两个结果(对应empById、empById1,结果缓存,直接读取),第二次就是后面再次创建调用SqlSession,再次执行了sql语句

2) 同一个SqlSession但是查询条件不同
3) 同一个SqlSession两次查询期间执行了任何一次增删改操作
(因为任意一次增删改会清除缓存,查询数据更新)

4) 同一个SqlSession两次查询期间手动清空了缓存
sqlSession1.clearCache();

2、MyBatis的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取

(二级缓存需要手动设置,一级不用)


二级缓存开启的条件:
a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
b>在映射文件中设置标签<cache />
c>二级缓存必须在SqlSession关闭或提交之后有效

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

public void testCache() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);
        Emp empById = mapper.getEmpById(1);
        System.out.println(empById);
        sqlSession.close();//数据默认保存到一级缓存,只要关闭或提交sqlSession后才会将存入二级缓存
        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp empById1 = mapper1.getEmpById(1);
        System.out.println(empById1);
    }
}

上述代码没有用工具类,因为要确保。通过同一个SqlSessionFactory创建的SqlSession查询
使二级缓存失效的情况:

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


3、二级缓存的相关配置

在mapper配置文件中添加的cache标签可以设置一些属性:

eviction属性:缓存回收策略
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。

flushInterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出

readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了
很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是
false。

4、MyBatis缓存查询的顺序

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

5、整合第三方缓存EHCache(针对二级缓存,整合第三方缓存实现二级缓存

Ehcache 是一个流行的开源 Java 缓存框架,用于将数据存储在内存中,以提高应用程序的性能和响应速度。MyBatis 提供了对 Ehcache 的集成支持,可以将 Ehcache 作为 MyBatis 的二级缓存实现。

a>添加依赖

        <!-- 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>

b>各jar包功能

c>在resources下创建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="D:\software\ja\java\javaweb\Web-studying\mybatis-cache\temp-cache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

上面的路径是指将日志等存储到我们电脑的路径,如下是最后运行所生成的文件及其存放路径

配置文件说明

d>设置二级缓存的类型

在 MyBatis 的 XML 配置文件中,使用 <cache> 标签,通过设置 type 属性为 org.mybatis.caches.ehcache.EhcacheCache,可以启用 Ehcache 缓存作为二级缓存。这样配置后,MyBatis 将使用 Ehcache 来缓存查询结果,减少与数据库的交互次数,提高系统的性能。

在CacheMapper.xml文件中:

e>加入logback日志
存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。
在resources下创建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.crowd.mapper" level="DEBUG"/>
</configuration>

(这部分只要了解可以第三方配置即可)

 MyBatis的逆向工程

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成Java实体类、Mapper接口
、Mapper映射文件

1、创建逆向工程的步骤

a>添加依赖和插件 (在pom.xml文件中添加)

<!-- 依赖MyBatis核心包 -->
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</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>
                    <!-- 数据库连接池 -->
                    <dependency>
                        <groupId>com.mchange</groupId>
                        <artifactId>c3p0</artifactId>
                        <version>0.9.2</version>
                    </dependency>
                    <!-- MySQL驱动 -->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.8</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

b>创建MyBatis的核心配置文件

c>创建逆向工程的配置文件(文件名必须是:generatorConfig.xml

<?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/mybatis?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=UTF-8"
                         userId="root"
                        password="1234567">

        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="personal.september.mbg.bean"
        targetProject=".\src\main\java">
        <property name="enableSubPackages" value="true" /><!--设置为true则名字.名字可以设置成多层目录-->
        <property name="trimStrings" value="true" /><!--将字段前后的空格去掉,生成对应的实体类中的属性-->
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="personal.september.mbg.mapper"
        targetProject=".\src\main\resources">
        <property name="enableSubPackages" value="true" /><!--是否使用子包的意思-->
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER"
        targetPackage="personal.september.mbg.mapper" targetProject=".\src\main\java">
        <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/><!--domainObjectName设置的是当前实体类的名字-->
                <!--设置完后,Mapper接口和映射文件都会根据其来起名,EmpMapper.xml,接口名EmpMapper-->
        <table tableName="t_dept" domainObjectName="Dept"/>
        </context>
        </generatorConfiguration>

(注意是userId不是username)

我们知道到这一步后,文件目录如下

在配置完成后点击下图阴影部分

再看文件目录可以发现,生成很多之前我们需要手动创建的文件

(注意,

1、上述自动构建的过程,只是满足我们单表操作的需求。记得utils包下的工具类等要自己取创建,properitise文件等。(只是生成基本的数据表对应的实体类,接口和配置文件等)

2、如果想要再次生成已经生成的文件,记得把原来的文件删除,避免在原有基础上追加出现问题。

3、在接口中生成的基本的增删改查,且生成的实体类只有简单的getter和setter方法,没有toString,要自己手动添加。(属性名有一定规律,符合字段的驼峰形式,例如emp_id

字段对应的属性名empId)

4、生成后我们在自己完善mybatis-config.xml内容。

5、MyBatis3Simple: 生成基本的CRUD(清新简洁版)
      MyBatis3: 生成带条件的CRUD(奢华尊享版)

(CRUD是指在做计算处理时的增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写。主要被用在描述软件系统中DataBase或者持久层的基本操作功能。)

下面将会生成Mybatis3

(如果是在之前生成了的基础上再去进行如下操作,记得删掉之前自动生成的文件)

在generatorConfig.xml中修改targetRuntime

再执行

结果如图

(和前面的区别主要就是生成的接口方法更多更全面

(记得如果要用@Test注解,使用测试单元,要在配置文件添加junit依赖

<!--junit测试-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

发现如下问题,

答案是:pom.xml文件中要把MySQL驱动配置放在<build><build>标签外面,而且我也修改了这个版本,应该和版本没关系。

创建测试文件去使用自动生成的方法,发现还挺好用。

我们要根据方法名知道其用法,上述代码中selectByPrimaryKey是根据主键去查询,

empExample.createCriteria().andEmpNameEqualTo("紫紫").andAgeGreaterThan(3);
empExample.or().andGenderEqualTo("女");也是根据其意思知道,逻辑是匹配名字为紫紫且年龄大于3的数据,还有将性别为女的记录全部输出。

创建条件对象,通过andXXX方法为SQL添加查询添加,每个条件之间是and关系,将之前添加的条件通过or拼接其他条件。

public void testMBG(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("大大");
        List<Emp> emps = mapper.selectByExample(empExample);
        emps.forEach(System.out::println);

        Emp emp1 = new Emp(null,"小紫",null,"女",3);
        int i = mapper.updateByExampleSelective(emp1, empExample);
        System.out.println(i);
}

上面对比结果可以知道,一些方法的用法,尤其是selective的方法,和之前的清晰简洁版不一样的是,会对一些条件进行判断,如上面使用的方法(updateByExampleSelective(emp1, empExample);)的意思就是对比empExample,如果emp1中有条件为null(即未被赋值条件)时不会直接用null覆盖原来的值,而简洁版生成的方法,会将null直接覆盖。

分页插件

1、分页插件使用步骤

先了解一下相关知识

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  
(当前为第一页,每页数据有4条数据,第一页第一条数据索引为0
pageSize=4,pageNum=3,index=8 limit 8,4   
(当前为第三页,每页数据有4条数据,第三页第一条数据索引为2X4=8,前面有两页共8条数据,又因为索引从0开始,所以就是原本为9-1=8.直接2X4=8的规律即index=(pageNum-1)*pageSize
pageSize=4,pageNum=6,index=20 limit 20,4
(当前为第六页,每页数据有4条数据,第六页第一条数据索引为5X4=20

首页 上一页 2 3 4 5 6 下一页 末页 (一般的样式都是这样的)

a>添加依赖

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.0</version>
        </dependency>

b>配置分页插件
在MyBatis的核心配置文件中配置插件(注意标签位置,有顺序的)

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

2、分页插件的使用

public void testPage(){
       SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //查询功能之前开启分页功能
        Page<Object> page = PageHelper.startPage(1, 4);
        List<Emp> list = mapper.selectByExample(null);
        list.forEach(System.out::println);
        System.out.println(page);
    }

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

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

 如下代码测试,结果确实只打印四条数据

当我们打印输出一下page的值时可以看到关于分页的相关数据

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

public void testPage(){
       SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //查询功能之前开启分页功能
        Page<Object> page = PageHelper.startPage(1, 4);
        List<Emp> list = mapper.selectByExample(null);
        //查询功之后可以获取分页相关的所有数据
        PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);
        System.out.println(page);
        System.out.println("------------");
        System.out.println(pageInfo);
    }

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

如下<Emp>表示的泛型为当前数据要转化的实体类类型

(上图最后面只输出了1-4范围empid的数据,因为上上面代码执行的查询结果就是输出四条)

c>分页相关数据(常用数据):
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码

isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]
(这是为后面实现ssm整合时提的基础知识,分页的内容)

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

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

相关文章

C语言基础知识点(六)二维数组指针和地址

#include <stdio.h>int main() {int a[2][3] {2, 4, 6,8, 10, 12};printf("a:%p, a1:%p\n", a, a 1); // 相差3*sizeof&#xff08;int&#xff09;12&#xff0c;二维数组名是一个指向每一行的指针&#xff0c;a:0061FF08, a1:0061FF14prin…

Redis Part1

单体架构&#xff1a;一台Web服务器、一台数据库服务器。 1.了解NoSql 什么是Nosql&#xff1f; NoSQL&#xff0c;即Not-Only-SQL&#xff0c;意思就是我们干事情不能只用SQL&#xff0c;泛指非关系型的数据库&#xff01;NoSQL定位&#xff1a;作为关系型数据库的补充&am…

信息安全三级概述

信息安全三级概述

C语言之const

C语言之const const修饰全局变量 此时全局变量只能使用但是不能修改&#xff0c; 如果直接拿全局变量修改值&#xff0c;编译直接报错 如果使用全局变量的地址修改值&#xff0c;运行时程序异常结束 const修饰普通局部变量 可以读取变量的值 不能直接通过变量进行修改值&a…

开源库源码分析:Okhttp源码分析(一)

开源库源码分析&#xff1a;OkHttp源码分析 导言 接下来就要开始分析一些常用开源库的源码了&#xff0c;作为最常用的网络请求库&#xff0c;OkHttp以其强大的功能深受Android开发者的喜爱&#xff08;比如说我&#xff09;&#xff0c;还有对该库进行二次封装而成的热门库&a…

为何红黑树在B/B+树之上仍然占据重要地位?

为何红黑树在B/B树之上仍然占据重要地位&#xff1f; 引言二、红黑树和B/B树的基本原理2.1、红黑树的特点和性质2.2、B/B树的特点和性质2.3、红黑树和B/B树的比较 三、B/B树相对于红黑树的优势四、红黑树仍然占据重要地位的原因总结 博主简介 &#x1f4a1;一个热爱分享高性能服…

成都营运《乡村振兴战略下传统村落文化旅游设计》许少辉八一著作

成都营运《乡村振兴战略下传统村落文化旅游设计》许少辉八一著作

【深度学习】 Python 和 NumPy 系列教程(廿七):Matplotlib详解:3、多子图和布局:散点矩阵图(Scatter Matrix Plot)

目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 3、多子图和布局 1. subplot()函数 2. subplots()函数 3. 散点矩阵图&#xff08;Scatter Matrix Plot&#xff09; 一、前言 Python是一种高级编程语言&#xff0c;由Guido van Rossum于…

2327. 知道秘密的人数;1722. 执行交换操作后的最小汉明距离;2537. 统计好子数组的数目

2327. 知道秘密的人数 核心思想&#xff1a;动态规划&#xff0c;每天的人可以分为三种&#xff0c;可分享秘密的人&#xff0c;不可分享秘密的人&#xff0c;忘记秘密的人。定义f[i]为第i天可分享秘密的人&#xff0c;那么第(idelay ,iforget)天&#xff0c;会增加f[i]个可分…

广州口腔医院种植牙-广东省爱牙工程公益种牙,获湾区群众点赞

广州种植牙价格表-自2017年成立以来,广东省爱牙工程一直坚持以公益惠民为宗旨、公益种牙为服务方向,针对群众普遍存在的口腔健康问题,开展形式多样的公益性口腔医疗惠民活动。 广州种植牙费用表-日前,广东省爱牙工程“种植牙惠民行动”第二十季已正式启动。据广东省爱牙工程官方…

DataGrip 2023 年下载、安装教程、亲测可用

文章目录 前言1. 下载2. 安装3、DataGrip 常用操作4 推荐阅读 前言 DataGrip 是 JetBrains 发布的多引擎数据库环境&#xff0c;支持 MySQL 和 PostgreSQL&#xff0c;Microsoft SQL Server 和 Oracle&#xff0c;Sybase&#xff0c;DB2&#xff0c;SQLite&#xff0c;还有 Hy…

窜货链接的有效治理流程

当商跨区域销售时&#xff0c;但产生了窜货&#xff0c;窜货的根本是因为低价&#xff0c;虽然品牌都会禁止经销商窜货销售&#xff0c;但为了获得更多利润&#xff0c;很多经销商还是会悄悄做着窜货销售的行为&#xff0c;而窜货不仅会破坏渠道的正常发展&#xff0c;同时还会…

第六章 图 十、关键路径

开始顶点&#xff08;源点)&#xff1a; 在AOE网中仅有一个入度为0的顶点&#xff0c;称为开始顶点&#xff08;源点)&#xff0c;它表示整个工程的开始; 结束顶点&#xff08;汇点)&#xff1a; 也仅有一个出度为0的顶点&#xff0c;称为结束顶点&#xff08;汇点)&#xf…

Postman应用——初步了解postman

Postman 是一个用于构建和使用 API 的 API 平台&#xff0c;Postman 简化了 API 生命周期的每个步骤并简化了协作&#xff0c;可以更快地创建更好的 API。 Postman 包含一个基于Node.js的强大的运行时&#xff0c;允许您向请求&#xff08;request&#xff09;和分组&#xff…

redis缓存穿透、击穿、雪崩介绍

缓存穿透 概念 缓存穿透指某一特定时间批量请求打进来并访问了缓存和数据库都没有的key&#xff0c;此时会直接穿透缓存直达数据库&#xff0c;从而造成数据库瞬时压力倍增导致响应速度下降甚至崩溃的风险&#xff1b; 解决方案 一、通过布隆过滤器解决 原理&#xff1a;将…

关于content-type的理解

一.content-type的结论 告诉后端传过去的数据是什么类型的数据 二.没有请求体 (1)没有请求体的情况下content-type没有意义。 (2):图示 里面是没有请求体的 (3)有请求体的情况 二.常见的三种方式 (1)application/x-www-form-urlencoded(默认) 参数的表现形式: 传递之前可以…

ESIM实战文本匹配

引言 今天我们来实现ESIM文本匹配&#xff0c;这是一个典型的交互型文本匹配方式&#xff0c;也是近期第一个测试集准确率超过80%的模型。 我们来看下是如何实现的。 模型架构 我们主要实现左边的ESIM网络。 从下往上看&#xff0c;分别是 输入编码层(Input Ecoding) 对前…

变压器寿命预测(python代码,Logistic Regression模型预测效果一般,可以做对比实验)

1.数据来源官网&#xff1a;Data for: Root cause analysis improved with machine learning for failure analysis in power transformers - Mendeley Data 点Download All 10kb即可下载数据 2.下载下来后是这样 每一列的介绍&#xff1a; Hydrogen 氢气&#xff1b; Oxyge…

低代码开源项目整理

低代码是基于可视化和模型驱动理念&#xff0c;结合云原生与多端体验技术&#xff0c;它能够在多数业务场景下实现大幅度的提效降本&#xff0c;为专业开发者提供了一种全新的高生产力开发范式。下面就来分享几个值得学习和使用的前端低代码开源项目&#xff0c;更深入地了解什…

八股——const 关键字

1.const作用 作用&#xff1a;const用于保护指针指向数据不被修改 测试代码1 显示数组的函数不小心修改了指针指向的值&#xff0c;这时候没有加const关键字&#xff0c;编译器不会报错 #include <stdio.h> void showar(int ar[]);int main(void) {int ar[4]{2,3,4,5…