ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MyBatis Plus核心功能与最佳实践解析

MyBatis Plus核心功能与最佳实践解析 1. MyBatis Plus核心价值解析作为MyBatis的增强工具包MyBatis Plus在保留原生MyBatis所有特性的基础上通过内置通用Mapper和Service显著减少了约80%的样板代码量。我在实际企业级项目开发中发现团队采用MyBatis Plus后单表CRUD操作的平均开发时间从原来的2小时缩短至15分钟。其核心优势主要体现在三个方面自动化SQL生成通过TableName和TableField注解映射实体与表结构无需手动编写基础CRUD的XML配置条件构造器QueryWrapper和UpdateWrapper支持链式调用可构建复杂查询条件而不必接触原生SQL插件体系分页插件、性能分析插件等开箱即用解决了传统MyBatis需要自行集成第三方组件的痛点重要提示MyBatis Plus并非要完全替代MyBatis对于需要高度定制SQL的复杂场景仍建议使用原生MyBatis方式实现2. 环境搭建与基础配置2.1 项目依赖引入Spring Boot项目中只需添加starter依赖即可自动配置大部分功能Gradle配置同理dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency2.2 核心配置项详解在application.yml中建议配置以下参数mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL日志输出 map-underscore-to-camel-case: true # 自动驼峰转换 global-config: db-config: id-type: auto # 主键策略 logic-delete-field: deleted # 逻辑删除字段 logic-not-delete-value: 0 logic-delete-value: 13. 核心功能深度实践3.1 实体映射与CRUD接口实体类注解配置示例Data TableName(sys_user) // 显式指定表名 public class User { TableId(type IdType.AUTO) // 主键策略 private Long id; TableField(username) // 字段映射 private String name; TableField(exist false) // 非表字段 private String tempData; }Service层继承增强接口即可获得全套CRUD方法public interface UserService extends IServiceUser {} Service public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService {}3.2 条件构造器高级用法复杂查询示例包含嵌套条件QueryWrapperUser query new QueryWrapper(); query.select(id, username) .like(username, admin) .and(wrapper - wrapper .gt(age, 18) .or() .isNotNull(email) ) .orderByDesc(create_time);更新操作避免全表覆盖的正确姿势UpdateWrapperUser update new UpdateWrapper(); update.set(password, 123456) .eq(status, 1) .apply(login_count login_count 1); // 原子递增4. 批量操作性能优化4.1 removeByIds与removeBatchByIds对比两种批量删除方式的本质区别// 方式1拼接单个DELETE语句推荐 ListLong ids Arrays.asList(1L, 2L, 3L); userService.removeByIds(ids); // 方式2生成多条DELETE语句3.5.0版本已优化 userService.removeBatchByIds(ids, 100); // 批次大小实测性能对比万级数据操作类型耗时(ms)内存占用(MB)单条循环删除2850120removeByIds32045removeBatchByIds410504.2 批量插入最佳实践使用saveBatch时的三个关键参数ListUser userList generateUsers(10000); // 事务批处理配置 userService.saveBatch(userList, 1000); // 批次大小踩坑记录MySQL默认驱动不支持rewriteBatchedStatements时批量插入会退化为单条执行需在JDBC URL添加rewriteBatchedStatementstrue参数5. 联表查询与分页方案5.1 多表关联实现策略虽然MyBatis Plus不直接支持联表但可通过以下方式实现方案1自定义SQL分页插件Select(SELECT u.*, d.dept_name FROM user u LEFT JOIN dept d ON u.dept_idd.id) IPageUserDeptVO selectUserDeptPage(IPage? page, Param(ew) WrapperUser wrapper);方案2多次查询内存组装适合数据量小场景public IPageUserDeptVO getUserDeptPage(PageUser page) { // 先查主表 IPageUser userPage userMapper.selectPage(page, null); // 提取关联ID批量查询 ListLong deptIds userPage.getRecords().stream() .map(User::getDeptId) .collect(Collectors.toList()); MapLong, Dept deptMap deptService.listByIds(deptIds).stream() .collect(Collectors.toMap(Dept::getId, Function.identity())); // 内存组装 return userPage.convert(user - { UserDeptVO vo new UserDeptVO(); BeanUtils.copyProperties(user, vo); vo.setDeptName(deptMap.get(user.getDeptId()).getName()); return vo; }); }5.2 分页插件配置要点必须注册分页插件才能生效Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }分页查询标准写法PageUser page new Page(1, 10); // 当前页, 每页数量 QueryWrapperUser query new QueryWrapper(); query.eq(status, 1); IPageUser result userService.page(page, query);6. 生产环境避坑指南6.1 逻辑删除的注意事项全局配置逻辑删除字段后查询会自动过滤已删除数据需要查询已删除数据时使用InterceptorIgnore注解InterceptorIgnore(illegalSql true) ListUser selectAllIncludeDeleted();6.2 字段类型映射陷阱Java类型与数据库类型不匹配时的解决方案TableField(typeHandler JacksonTypeHandler.class) // JSON字段处理 private ListString tags; TableField(jdbcType JdbcType.VARCHAR) // 明确指定jdbc类型 private String uuid;6.3 租户数据隔离方案多租户系统配置示例public class TenantInterceptor implements InnerInterceptor { Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // 自动添加tenant_id条件 } }7. 扩展功能实战7.1 自动填充功能实现元数据自动填充创建时间、更新时间等Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } }7.2 枚举类型处理优雅处理数据库枚举值Getter public enum UserStatus { NORMAL(1, 正常), LOCKED(2, 锁定); EnumValue // 标记数据库存储值 private final int code; private final String desc; // 构造方法... }7.3 SQL注入器扩展自定义通用方法示例public class BatchInsertInjector extends DefaultSqlInjector { Override public ListAbstractMethod getMethodList(Class? mapperClass) { ListAbstractMethod methods super.getMethodList(mapperClass); methods.add(new BatchInsert()); // 添加自定义方法 return methods; } }8. 性能监控与优化8.1 SQL执行分析启用性能分析插件Bean public PerformanceInterceptor performanceInterceptor() { PerformanceInterceptor interceptor new PerformanceInterceptor(); interceptor.setMaxTime(1000); // 慢SQL阈值(ms) interceptor.setFormat(true); // 格式化SQL return interceptor; }8.2 二级缓存整合整合Redis作为二级缓存mybatis-plus: configuration: cache-enabled: trueCacheNamespace(implementation MybatisRedisCache.class) public interface UserMapper extends BaseMapperUser {}9. 复杂查询解决方案9.1 动态表名处理实现按月分表的动态路由public class DynamicTableNameParser implements IKeyGenerator { Override public String process(MappedStatement ms, Object parameter, String tableName) { if (log.equals(tableName)) { return tableName _ LocalDate.now().getMonthValue(); } return tableName; } }9.2 存储过程调用调用MySQL存储过程示例Select(CALL proc_get_user_stats(#{userId}, #{resultModeOUT, jdbcTypeCURSOR})) Options(statementType StatementType.CALLABLE) MapString, Object callUserStatsProc(Param(userId) Long userId);10. 版本升级指南从3.x升级到最新版的注意事项包路径变更com.baomidou.mybatisplus→com.baomidou.mybatisplus.extension移除JSR310日期处理依赖改为内置支持Lambda表达式API调整// 旧版 QueryWrapperUser query new QueryWrapper(); query.lambda().eq(User::getName, test); // 新版 LambdaQueryWrapperUser query new LambdaQueryWrapper(); query.eq(User::getName, test);分页对象优化Pagination→Page自动填充策略变更TableField(fill FieldFill.INSERT)需要配合MetaObjectHandler使用
返回列表