SpringBoot集成MyBatis-Plus:分页、条件查询与SQL日志全攻略
2025.09.18 16:02浏览量:0简介:本文详细介绍SpringBoot项目中集成MyBatis-Plus框架的分页插件配置、条件构造器使用及SQL打印日志的开启方法,助力开发者高效完成数据层开发。
SpringBoot集成MyBatis-Plus:分页、条件查询与SQL日志全攻略
一、MyBatis-Plus核心功能概述
MyBatis-Plus是MyBatis的增强工具,在保持原有功能基础上提供分页查询、条件构造器、Lambda表达式等特性。其核心优势在于:
- 零SQL编写:通过条件构造器实现复杂查询
- 高性能分页:内置物理分页插件
- 开发效率提升:减少90%的CRUD代码量
- SQL透明化:支持完整的SQL日志输出
在SpringBoot项目中,通过Maven引入核心依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
二、分页插件配置与使用
1. 插件配置原理
MyBatis-Plus分页插件通过拦截器实现物理分页,核心类为PaginationInnerInterceptor
。其工作机制包含:
- SQL重写:在原始SQL后追加
LIMIT
子句 - 分页参数计算:自动处理页码与每页条数的换算
- 结果集封装:将查询结果转换为
Page
对象
2. 完整配置示例
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件配置
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(
DbType.MYSQL // 数据库类型
);
paginationInterceptor.setMaxLimit(1000L); // 单页最大限制
paginationInterceptor.setOverflow(true); // 溢出总页数处理
interceptor.addInnerInterceptor(paginationInterceptor);
return interceptor;
}
}
3. 分页查询实现
服务层实现示例:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
public IPage<User> queryPage(Integer current, Integer size) {
// 创建分页对象
Page<User> page = new Page<>(current, size);
// 执行分页查询
return userMapper.selectPage(page, null);
}
}
控制器层调用:
@GetMapping("/users")
public Result getUsers(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
IPage<User> page = userService.queryPage(pageNum, pageSize);
return Result.success(page);
}
4. 高级配置选项
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
maxLimit | Long | null | 单页最大记录数限制 |
overflow | Boolean | false | 超出最大页数处理方式 |
countSql | Boolean | true | 是否执行COUNT查询 |
optimal | Boolean | false | 优化COUNT查询(子查询优化) |
三、条件查询构造器详解
1. Wrapper体系结构
MyBatis-Plus提供四种条件构造器:
QueryWrapper
:基础条件构造LambdaQueryWrapper
:Lambda表达式支持UpdateWrapper
:更新条件构造LambdaUpdateWrapper
:Lambda更新构造
2. 常用查询方法
// 1. 等于查询
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getAge, 25);
// 2. 范围查询
wrapper.between(User::getAge, 20, 30)
.ge(User::getCreateTime, LocalDateTime.now().minusDays(7));
// 3. 模糊查询
wrapper.like(User::getName, "张")
.or()
.likeRight(User::getPhone, "138");
// 4. 排序
wrapper.orderByDesc(User::getCreateTime)
.orderByAsc(User::getAge);
// 5. 嵌套条件
wrapper.and(w -> w.eq(User::getStatus, 1)
.or()
.eq(User::getType, 2));
3. 链式调用最佳实践
推荐采用分段构建方式提高可读性:
public List<User> queryComplex(String keyword, Integer minAge) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
// 基础条件
wrapper.eq(User::getStatus, 1);
// 关键词搜索
if (StringUtils.isNotBlank(keyword)) {
wrapper.like(User::getName, keyword)
.or()
.like(User::getEmail, keyword);
}
// 年龄范围
if (minAge != null) {
wrapper.ge(User::getAge, minAge);
}
// 排序
wrapper.orderByDesc(User::getCreateTime);
return userMapper.selectList(wrapper);
}
四、SQL打印日志配置
1. 日志输出级别配置
在application.yml
中配置:
logging:
level:
com.baomidou.mybatisplus: debug
com.baomidou.mybatisplus.core.conditions: trace
2. 性能分析插件
启用SQL性能分析插件:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 性能分析插件
interceptor.addInnerInterceptor(new IllegalSQLInnerInterceptor());
interceptor.addInnerInterceptor(new SqlExplainInterceptor(
new SqlExplainInterceptor.ExplainStrategy() {
@Override
public String getExplainStrategy() {
return "SERIALIZABLE"; // 执行计划策略
}
}
));
return interceptor;
}
3. 日志格式优化
推荐使用Logback配置彩色日志:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %magenta(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.baomidou.mybatisplus" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
4. 执行计划解读
典型SQL日志示例:
2023-05-20 14:30:45.123 DEBUG c.b.m.c.i.m.MybatisMapperMethod - ==> Preparing: SELECT id,name,age,create_time FROM user WHERE (age = ? AND status = ?) ORDER BY create_time DESC LIMIT ?,?
2023-05-20 14:30:45.125 DEBUG c.b.m.c.i.m.MybatisMapperMethod - ==> Parameters: 25(Integer), 1(Integer), 0(Integer), 10(Integer)
2023-05-20 14:30:45.150 DEBUG c.b.m.c.i.m.MybatisMapperMethod - <== Total: 10
执行计划分析要点:
- 参数绑定:确认参数值正确传递
- SQL重写:验证分页参数是否正确追加
- 索引使用:检查是否命中预期索引
- 执行时间:关注慢查询(>500ms)
五、常见问题解决方案
1. 分页失效问题
- 现象:返回所有数据而非分页结果
- 原因:
- 未正确配置分页插件
- 查询方法未返回
IPage
类型 - 存在其他拦截器冲突
解决方案:
// 错误示例(返回List导致分页失效)
public List<User> wrongPageQuery(Page<User> page) {
return userMapper.selectPage(page, null).getRecords(); // 错误方式
}
// 正确示例
public IPage<User> correctPageQuery(Page<User> page) {
return userMapper.selectPage(page, null); // 正确方式
}
2. 条件查询N+1问题
- 现象:多次执行相似SQL
优化方案:
// 优化前(多次查询)
List<User> users = userMapper.selectList(null);
for (User user : users) {
Department dept = deptMapper.selectById(user.getDeptId());
user.setDeptName(dept.getName());
}
// 优化后(使用关联查询)
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User::getId, User::getName, User::getDeptId)
.inSql(User::getDeptId, "SELECT id FROM department WHERE status = 1");
List<User> users = userMapper.selectList(wrapper);
3. SQL日志不输出
- 检查项:
- 日志级别是否设置为DEBUG
- 是否配置了正确的Logger名称
- 是否被其他AOP切面拦截
- 数据库驱动是否支持日志输出
六、性能优化建议
分页参数优化:
- 首页查询建议默认页大小10-20条
- 深度分页(>1000页)建议使用游标分页
- 后台任务分页建议设置
maxLimit=500
条件查询优化:
// 优化示例:减少OR条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.in(User::getStatus, Arrays.asList(1, 2, 3))
.eq(User::getType, 1);
// 替代方案(性能更好):
// SELECT * FROM user WHERE (status = 1 OR status = 2 OR status = 3) AND type = 1
SQL日志分析:
- 重点关注全表扫描警告
- 检查索引使用情况
- 分析执行计划中的”Extra”字段
七、进阶功能探索
1. 动态表名支持
@Bean
public MybatisPlusInterceptor dynamicTableNameInterceptor() {
return new MybatisPlusInterceptor()
.addInnerInterceptor(new DynamicTableNameInnerInterceptor() {
@Override
public String dynamicTableName(String sql, String tableName) {
// 根据业务逻辑返回实际表名
return "user_" + LocalDate.now().getYear();
}
});
}
2. 多数据源支持
@Configuration
@MapperScan("com.example.mapper.*")
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(masterDataSource());
factory.setPlugins(new Interceptor[]{
paginationInnerInterceptor(),
sqlExplainInterceptor()
});
return factory.getObject();
}
}
八、总结与最佳实践
配置优先级:
- 分页插件 > 性能分析 > 动态表名
- 日志级别建议开发环境DEBUG,生产环境INFO
代码规范建议:
// 推荐写法(方法职责单一)
public PageResult<UserDTO> queryUsers(UserQueryParam param) {
// 参数校验
validateParam(param);
// 构建查询条件
LambdaQueryWrapper<User> wrapper = buildQueryWrapper(param);
// 执行分页查询
Page<User> page = new Page<>(param.getPageNum(), param.getPageSize());
IPage<User> result = userMapper.selectPage(page, wrapper);
// 结果转换
List<UserDTO> dtos = convertToDTO(result.getRecords());
return new PageResult<>(dtos, result.getTotal());
}
监控指标:
- 平均分页查询耗时
- 条件查询命中率
- SQL执行错误率
通过合理配置MyBatis-Plus的分页插件、条件查询和SQL日志功能,可以显著提升SpringBoot项目的开发效率和运维能力。建议开发团队建立标准的MyBatis-Plus使用规范,定期分析SQL日志,持续优化数据库访问性能。
发表评论
登录后可评论,请前往 登录 或 注册