1. MyBatis使用 PageHelper 分页查询插件的详细配置
文章目录
- 1. MyBatis使用 PageHelper 分页查询插件的详细配置
- 2. 准备工作
- 3. 使用传统的 limit 关键字进行分页
- 4. PageHelper 插件(配置步骤)
- 4.1 第一步:引入依赖
- 4.2 第二步:在mybatis-config.xml文件中配置插件
- 4.3 第三步:编写Java代码
- 5. 总结:
- 6. 最后:
2. 准备工作
数据表结构的设计,数据表名为:t_car
t_car 表中的数据信息:
在pom.xml
文件当中配置相关的依赖的 jar 包如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rainbowsea</groupId>
<artifactId>mybatis-005-crud-blog</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- mybatis 的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- 引入 logback的依赖,这个日志框架实现了slf4j 规范-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
</project>
配置 logback 的配置文件,用于打印显示,我们的日志信息,方便我们查看我们的运行过程,效果。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--mybatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
配置 MyBatis 的核心配置文件,
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 使用 <package> 还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 -->
<package name="com.rainbowsea.mybatis.pojo"/>
</typeAliases>
<environments default="mybatis">
<environment id="mybatis">
<!-- MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="MySQL123"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致-->
<package name="com.rainbowsea.mybatis.mapper"></package>
</mappers>
</configuration>
对照 t_car 创建的ORM 映射的 Car 类
注意:在MyBatis 当中对应的ORM ,一般在框架里对应的 Bean实体类,一定要实现该 set 和 get 方法以及无参数构造方法,无法框架无法使用反射机制,进行操作 。
建议用包装类,这样可以防止 Null的问题,因为(简单类型 int num = null ,是不可以赋值为 null)的编译无法通过
package com.rainbowsea.mybatis.pojo;
public class Car {
// 数据库表当中的字段应该和pojo类的属性一一对应
// 建议使用包装类,这样可以防止null的问题
private Long id;
private String carNum;
private String brand;
private Double guidePrice;
private String produceTime;
private String carType;
public Car() {
}
public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
this.id = id;
this.carNum = carNum;
this.brand = brand;
this.guidePrice = guidePrice;
this.produceTime = produceTime;
this.carType = carType;
}
@Override
public String toString() {
return "Car{" +
"id=" + id +
", carNum='" + carNum + '\'' +
", brand='" + brand + '\'' +
", guidePrice=" + guidePrice +
", produceTime='" + produceTime + '\'' +
", catType='" + carType + '\'' +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCarNum() {
return carNum;
}
public void setCarNum(String carNum) {
this.carNum = carNum;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Double getGuidePrice() {
return guidePrice;
}
public void setGuidePrice(Double guidePrice) {
this.guidePrice = guidePrice;
}
public String getProduceTime() {
return produceTime;
}
public void setProduceTime(String produceTime) {
this.produceTime = produceTime;
}
public String getcarType() {
return carType;
}
public void setcarType(String catType) {
this.carType = catType;
}
}
3. 使用传统的 limit 关键字进行分页
mysql的 limit 后面两个数字:
- 第一个数字:startIndex(起始下标。下标从0开始。)
- 第二个数字:pageSize(每页显示的记录条数)
假设已知页码pageNum,还有每页显示的记录条数pageSize,第一个数字可以动态的获取吗?
startIndex = (pageNum - 1) * pageSize
所以,标准通用的mysql分页SQL:
select
*
from
tableName ......
limit
(pageNum - 1) * pageSize, pageSize
package com.rainbowsea.mybatis.mapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
/**
* 分页查询
*
* @param startIndex 起始下标
* @param pageSize 每页显示的记录条数
* @return
*/
List<Car> selectByPage(@Param("startIndex") int startIndex, @Param("pageSize") int pageSize);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
<!-- id 要是 namespace 对应接口上的方法名: -->
<select id="selectByPage" resultType="Car">
select id, car_num, brand, guide_price, produce_time, car_type
from t_car limit #{startIndex}, #{pageSize}
</select>
</mapper>
运行测试:
@Test
public void testSelectByPage() throws IOException {
// 获取每页显示的记录条数
int pageSize = 3;
// 显示第几页:页码
int pageNum = 1;
// 计算开始下标
int startIndex = (pageNum - 1) * pageSize;
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
SqlSession sqlSession = sqlSessionFactory.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectByPage(startIndex, pageSize);
cars.forEach(car -> {
System.out.println(car);
});
sqlSession.close();
}
4. PageHelper 插件(配置步骤)
使用PageHelper插件进行分页,更加的便捷。
4.1 第一步:引入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.1</version>
</dependency>
4.2 第二步:在mybatis-config.xml文件中配置插件
typeAliases标签下面进行配置:注意:<plugins> 标签的位置,可以根据报错信息进行修正,确定正确的顺序位置。
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 启用驼峰命名映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 延迟加载的全局开关,默认值是 false 不开启 (简单的说就是:所有只要但凡带有分布的,都采用延迟加载)-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<!-- 起别名-->
<typeAliases>
<!-- 使用 <package> 还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 -->
<package name="com.rainbowsea.mybatis.pojo"/>
</typeAliases>
<!-- mybatis 分页的拦截器-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<environments default="mybatis">
<environment id="mybatis">
<!-- MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="MySQL123"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致-->
<package name="com.rainbowsea.mybatis.mapper"></package>
</mappers>
</configuration>
4.3 第三步:编写Java代码
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
List<Car> selectAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
<select id="selectAll" resultType="Car">
select id, car_num, brand, guide_price, produce_time, car_type
from t_car
</select>
</mapper>
关键点:
- 在查询语句之前开启分页功能。
- 在查询语句之后封装PageInfo对象。(PageInfo对象将来会存储到request域当中。在页面上展示。)
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
public class CarMapperTest {
@Test
public void testSelectAll() throws IOException {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
SqlSession sqlSession = sqlSessionFactory.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 一定一定一定要注意,在执行DQL语句之前,开启分页功能
int pageNum = 2;
int pageSize = 3;
PageHelper.startPage(pageNum, pageSize);
List<Car> cars = mapper.selectAll();
// 封装分页信息对象new PageInfo()
// PageInfo 对象是PageHelper 插件提供的,用来封装分页相关的信息的对象
PageInfo<Car> carPageInfo = new PageInfo<>();
System.out.println(carPageInfo);
// 获取分页信息对象
PageInfo<Car> pageInfo = new PageInfo<>(cars, 5);
System.out.println(pageInfo);
sqlSession.close();
// PageInfo{pageNum=0, pageSize=0, size=0, startRow=0, endRow=0, total=0, pages=0, list=null,
// prePage=0, nextPage=0, isFirstPage=false, isLastPage=false, hasPreviousPage=false, hasNextPage=false,
// navigatePages=0, navigateFirstPage=0, navigateLastPage=0, navigatepageNums=null}
}
PageInfo{pageNum=0, pageSize=0, size=0, startRow=0, endRow=0, total=0, pages=0, list=null, prePage=0, nextPage=0, isFirstPage=false, isLastPage=false, hasPreviousPage=false, hasNextPage=false, navigatePages=0, navigateFirstPage=0, navigateLastPage=0, navigatepageNums=null}
对执行结果进行格式化:
PageInfo{pageNum=2, pageSize=3, size=2, startRow=4, endRow=5, total=5, pages=2, list=Page{count=true, pageNum=2, pageSize=3, startRow=3, endRow=6, total=5, pages=2, reasonable=false, pageSizeZero=false}[Car{id=141, carNum=‘222’, brand=‘迈巴赫’, guidePrice=100.00, produceTime=‘2021-1’, carType=‘燃油车’}, Car{id=142, carNum=‘333’, brand=‘长城’, guidePrice=10.00, produceTime=‘2020-6’, carType=‘燃油车’}], prePage=1, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true, hasNextPage=false, navigatePages=5, navigateFirstPage=1, navigateLastPage=2, navigatepageNums=[1, 2]}
5. 总结:
假设已知页码pageNum,还有每页显示的记录条数pageSize,第一个数字可以动态的获取吗?
startIndex = (pageNum - 1) * pageSize
6. 最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”