PageHelper
使用

//EmpServiceImpl
@Override
public PageResult page(EmpQueryParam queryParam) {
//1. 设置PageHelper分页参数
PageHelper.startPage(queryParam.getPage(), queryParam.getPageSize());
//2. 执行查询
List empList = empMapper.list(queryParam);
//3. 封装分页结果
Page p = (Page) empList;
return new PageResult(p.getTotal(), p.getResult());
}
注意:
- PageHelper实现分页查询时,SQL语句的结尾一定一定一定不要加分号(;)。
- PageHelper只会对紧跟在其后的第一条SQL语句进行分页处理。
application.yml中,引入如下配置
pagehelper:
reasonable: true
helper-dialect: mysql
reasonable:分页合理化参数,默认值为false。当该参数设置为true时,pageNum<=0时会查询第一页,pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
数据绑定
package site.suiyue.pojo;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
/**
* 员工查询参数封装类
*/
@Data
public class EmpQueryParam {
private Integer page = 1; // 页码,默认值为1
private Integer pageSize = 10; // 每页大小,默认值为10
private String name; // 姓名
private Integer gender; // 性别
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate begin; // 入职开始时间
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate end; // 入职结束时间
}
为什么定义了一个实体类之后,下列代码简略了:
before:
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
@Autowired
private EmpService empService;
@GetMapping
public Result page(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
String name, Integer gender,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
log.info("查询请求参数: {}, {}, {}, {}, {}, {}", page, pageSize, name, gender, begin, end);
PageResult pageResult = empService.page(page, pageSize);
return Result.success(pageResult);
}
}
after:
@GetMapping
public Result page(EmpQueryParam empQueryParam) {
log.info("查询请求参数:{}", empQueryParam);
PageResult pageResult = empService.page(empQueryParam);
return Result.success(pageResult);
}
- 方法参数只有一个
EmpQueryParam对象。 - Spring 会自动将请求参数(如
page、name、begin等)绑定到该对象的对应属性上。 - 原来方法参数上的注解(如
@DateTimeFormat)移到了实体类的字段上,同样生效。
为什么不需要原来的那些参数和注解了?
- 自动绑定:Spring 会调用
EmpQueryParam的无参构造器创建对象,然后遍历请求参数,将参数名与对象的属性名匹配,通过 setter 方法赋值。 - 默认值:原来
@RequestParam(defaultValue = "1")的功能,现在通过实体类字段的初始值实现:private Integer page = 1;。当请求中没有page参数时,对象会保留这个初始值。 - 类型转换:
@DateTimeFormat移到begin和end字段上后,Spring 在将字符串"2026-03-04"赋值给LocalDate字段时会自动应用该格式。 - 参数集中管理:所有查询参数的定义(名称、类型、默认值、格式)都集中在
EmpQueryParam类中,便于复用和维护,也避免了多个接口重复编写相同参数列表。
动态SQL

<if>:判断条件是否成立,如果条件为true,则拼接SQL。
<where>:根据查询条件,来生成where关键字,并会自动去除条件前面多余的and或or。
concat 函数的基本作用
- 定义:
concat(str1, str2, ...)接收若干个字符串参数,将它们按顺序连接成一个新字符串。 - 示例:
concat('Hello', ' ', 'World')结果为'Hello World'
为什么必须用 concat 而不是直接拼接?
初学者容易写出类似 '%#{name}%' 的错误写法,但这在 MyBatis 中行不通,原因在于:
(1) #{} 预编译占位符不能在字符串字面量内
'%#{name}%'会被 MyBatis 当作普通字符串处理,其中的#{name}不会被解析成参数占位符,而是原样保留。最终传递给数据库的 SQL 可能变成:
e.name like '%#{name}%'
- 数据库找不到名为
name的列,或者将其视为固定字符串,查询结果必然出错。 - 正确的方式是使用
concat将%和参数值在 SQL 层面 拼接起来。#{name}单独出现,会被替换成?预编译占位符,参数值安全传入。
(2) 防止 SQL 注入
- 使用
#{}是预编译方式,MyBatis 会为参数值设置占位符?,并由数据库驱动进行转义处理。即使参数中包含特殊字符(如%、_、'),也能正确转义,避免 SQL 注入风险。 - 如果尝试用字符串拼接(如
'%' + #{name} + '%'在某些数据库中可行),但更容易引入注入漏洞,且不同数据库语法不统一。
Comments NOTHING