本文是 Java 系列教程从基础到进阶附完整代码示例收藏备用一、前言MyBatis-Plus 是 MyBatis 的增强工具在 MyBatis 的基础上只做增强不做改变为简化开发、提高效率而生。本文将带你从零搭建一个基于 MyBatis-Plus 的通用 CRUD 框架涵盖代码生成器、分页插件、逻辑删除、多租户等高级特性。学完本文你将掌握MyBatis-Plus 的快速集成与配置通用 CRUD 接口的封装代码生成器的使用与定制分页插件、性能分析插件的配置逻辑删除、自动填充、多租户实现二、快速开始2.1 引入依赖!-- Spring Boot 2.x/3.x -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version /dependency !-- 数据库驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- 代码生成器 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-generator/artifactId version3.5.5/version /dependency dependency groupIdorg.freemarker/groupId artifactIdfreemarker/artifactId version2.3.32/version /dependency2.2 配置数据源spring: datasource: url: jdbc:mysql://localhost:3306/mydb?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: # 开启SQL日志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 驼峰命名自动映射 map-underscore-to-camel-case: true global-config: db-config: # 逻辑删除字段 logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 # 全局表前缀 table-prefix: t_ # Mapper XML 位置 mapper-locations: classpath*:/mapper/**/*.xml # 实体包扫描别名 type-aliases-package: com.example.entity2.3 启动类配置SpringBootApplication MapperScan(com.example.mapper) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }三、基础 CRUD 操作3.1 实体类定义Data TableName(t_user) public class User { TableId(type IdType.AUTO) private Long id; private String username; private String email; private Integer age; TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; TableLogic TableField(fill FieldFill.INSERT) private Integer deleted; } // 主键策略枚举 public enum IdType { AUTO, // 数据库自增 INPUT, // 手动输入 ASSIGN_ID, // 雪花算法Long ASSIGN_UUID, // UUIDString NONE // 无策略 }3.2 Mapper 接口Mapper public interface UserMapper extends BaseMapperUser { // 继承 BaseMapper 获得基础 CRUD 方法 // 自定义 SQL 直接在这里声明 ListUser selectByAge(Param(age) Integer age); }3.3 Service 层封装// Service 接口 public interface UserService extends IServiceUser { // 自定义业务方法 ListUser getUsersByAge(Integer age); } // Service 实现 Service public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService { Override public ListUser getUsersByAge(Integer age) { return baseMapper.selectByAge(age); } // 批量插入优化 Transactional(rollbackFor Exception.class) public void batchInsert(ListUser users) { // 每 1000 条分批插入 int batchSize 1000; ListUser batch new ArrayList(batchSize); for (User user : users) { batch.add(user); if (batch.size() batchSize) { saveBatch(batch); batch.clear(); } } if (!batch.isEmpty()) { saveBatch(batch); } } }3.4 基础 CRUD 示例Autowired private UserService userService; // 新增 public void testInsert() { User user new User(); user.setUsername(张三); user.setEmail(zhangsanexample.com); user.setAge(25); boolean success userService.save(user); System.out.println(插入结果 success); System.out.println(生成ID user.getId()); } // 批量插入 public void testBatchInsert() { ListUser users new ArrayList(); for (int i 0; i 10; i) { User user new User(); user.setUsername(user i); user.setEmail(user i example.com); user.setAge(20 i); users.add(user); } boolean success userService.saveBatch(users); } // 根据 ID 查询 public void testSelectById() { User user userService.getById(1L); System.out.println(user); } // 条件查询 public void testSelectByCondition() { // 方式1QueryWrapper QueryWrapperUser wrapper new QueryWrapper(); wrapper.eq(age, 25) .like(username, 张) .orderByDesc(create_time); ListUser users userService.list(wrapper); // 方式2LambdaQueryWrapper类型安全 LambdaQueryWrapperUser lambdaWrapper new LambdaQueryWrapper(); lambdaWrapper.eq(User::getAge, 25) .like(User::getUsername, 张) .orderByDesc(User::getCreateTime); ListUser users2 userService.list(lambdaWrapper); } // 更新 public void testUpdate() { // 根据 ID 更新 User user new User(); user.setId(1L); user.setAge(26); userService.updateById(user); // 条件更新 LambdaUpdateWrapperUser wrapper new LambdaUpdateWrapper(); wrapper.set(User::getAge, 30) .eq(User::getUsername, 张三); userService.update(wrapper); } // 删除 public void testDelete() { // 逻辑删除配置后自动生效 userService.removeById(1L); // 物理删除 userService.remove(new QueryWrapperUser().eq(id, 1L)); }四、高级查询4.1 复杂条件构造Service public class UserQueryService { Autowired private UserService userService; // 多条件动态查询 public ListUser queryUsers(UserQueryDTO dto) { LambdaQueryWrapperUser wrapper new LambdaQueryWrapper(); // 动态条件拼接 wrapper.like(StringUtils.isNotBlank(dto.getUsername()), User::getUsername, dto.getUsername()) .eq(dto.getAge() ! null, User::getAge, dto.getAge()) .ge(dto.getStartTime() ! null, User::getCreateTime, dto.getStartTime()) .le(dto.getEndTime() ! null, User::getCreateTime, dto.getEndTime()) .in(dto.getIds() ! null !dto.getIds().isEmpty(), User::getId, dto.getIds()); return userService.list(wrapper); } // 分组聚合查询 public ListMapString, Object groupByAge() { QueryWrapperUser wrapper new QueryWrapper(); wrapper.select(age, count(*) as count) .groupBy(age) .having(count {0}, 5); return userService.listMaps(wrapper); } // 嵌套条件AND / OR public ListUser complexQuery() { LambdaQueryWrapperUser wrapper new LambdaQueryWrapper(); // (username 张三 OR username 李四) AND age 20 wrapper.nested(w - w.eq(User::getUsername, 张三) .or() .eq(User::getUsername, 李四)) .gt(User::getAge, 20); return userService.list(wrapper); } }4.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); // 乐观锁插件 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } } // 分页查询使用 Service public class UserPageService { Autowired private UserService userService; public PageUser queryUserPage(int current, int size, UserQueryDTO dto) { // 创建分页对象 PageUser page new Page(current, size); // 构建查询条件 LambdaQueryWrapperUser wrapper new LambdaQueryWrapper(); if (StringUtils.isNotBlank(dto.getUsername())) { wrapper.like(User::getUsername, dto.getUsername()); } if (dto.getAge() ! null) { wrapper.eq(User::getAge, dto.getAge()); } // 执行分页查询 return userService.page(page, wrapper); } // 返回结果处理 public PageResultUserVO getUserPage(int current, int size) { PageUser page queryUserPage(current, size, new UserQueryDTO()); // 实体转 VO ListUserVO voList page.getRecords().stream() .map(this::convertToVO) .collect(Collectors.toList()); return PageResult.of(voList, page.getTotal(), page.getCurrent(), page.getSize()); } }五、代码生成器5.1 快速生成代码public class CodeGenerator { public static void main(String[] args) { FastAutoGenerator.create( jdbc:mysql://localhost:3306/mydb?serverTimezoneAsia/Shanghai, root, 123456 ) // 全局配置 .globalConfig(builder - { builder.author(YourName) .outputDir(System.getProperty(user.dir) /src/main/java) .dateType(DateType.TIME_PACK) .commentDate(yyyy-MM-dd) .disableOpenDir(); }) // 包配置 .packageConfig(builder - { builder.parent(com.example) .entity(entity) .mapper(mapper) .service(service) .serviceImpl(service.impl) .xml(mapper.xml); }) // 策略配置 .strategyConfig(builder - { builder.addInclude(t_user, t_order, t_product) // 实体策略 .entityBuilder() .enableLombok() .enableTableFieldAnnotation() .logicDeleteColumnName(deleted) .addTableFills( new Column(create_time, FieldFill.INSERT), new Column(update_time, FieldFill.INSERT_UPDATE) ) // Mapper 策略 .mapperBuilder() .enableMapperAnnotation() .enableBaseResultMap() // Service 策略 .serviceBuilder() .formatServiceFileName(%sService) .formatServiceImplFileName(%sServiceImpl) // Controller 策略 .controllerBuilder() .enableRestStyle(); }) // 模板配置 .templateEngine(new FreemarkerTemplateEngine()) .execute(); } }5.2 自定义模板// 自定义 Controller 模板 .injectionConfig(builder - { MapString, String customFile new HashMap(); customFile.put(DTO.java, /templates/dto.java.ftl); customFile.put(VO.java, /templates/vo.java.ftl); builder.customFile(customFile); })六、高级特性6.1 自动填充Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, deleted, Integer.class, 0); // 自动填充当前用户ID Long userId getCurrentUserId(); this.strictInsertFill(metaObject, createBy, Long.class, userId); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); Long userId getCurrentUserId(); this.strictUpdateFill(metaObject, updateBy, Long.class, userId); } }6.2 乐观锁Entity public class Product { TableId private Long id; private String name; private Integer stock; Version private Integer version; } Service public class ProductService { Autowired private ProductMapper productMapper; // 乐观锁扣减库存 public boolean deductStock(Long productId, Integer quantity) { LambdaUpdateWrapperProduct wrapper new LambdaUpdateWrapper(); wrapper.eq(Product::getId, productId) .ge(Product::getStock, quantity) .setSql(stock stock - {0}, quantity); return productMapper.update(null, wrapper) 0; } }6.3 多租户Component public class TenantLineHandlerImpl implements TenantLineHandler { Override public Expression getTenantId() { // 从上下文获取当前租户ID Long tenantId TenantContextHolder.getTenantId(); return new LongValue(tenantId); } Override public String getTenantIdColumn() { return tenant_id; } Override public boolean ignoreTable(String tableName) { // 忽略多租户表 return sys_config.equals(tableName) || sys_dict.equals(tableName); } } // 配置多租户插件 Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor( new TenantLineInnerInterceptor(new TenantLineHandlerImpl()) ); return interceptor; }6.4 动态表名// 分表场景 public class DynamicTableNameHandler { public static void setTableName(String tableName) { RequestDataHolder.put(tableName, tableName); } } // 配置 Bean public DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() { DynamicTableNameInnerInterceptor interceptor new DynamicTableNameInnerInterceptor(); interceptor.setTableNameHandler((sql, tableName) - { String dynamicTable RequestDataHolder.get(tableName); return dynamicTable ! null ? dynamicTable : tableName; }); return interceptor; }七、性能优化7.1 批量操作优化// 配置批量操作 Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { MybatisSqlSessionFactoryBean factoryBean new MybatisSqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); // 配置批量执行器 org.apache.ibatis.session.Configuration configuration new org.apache.ibatis.session.Configuration(); configuration.setDefaultExecutorType(ExecutorType.BATCH); factoryBean.setConfiguration(configuration); return factoryBean.getObject(); } // 使用 SqlSession 批量插入 Autowired private SqlSessionFactory sqlSessionFactory; public void batchInsert(ListUser users) { SqlSession session sqlSessionFactory.openSession(ExecutorType.BATCH); try { UserMapper mapper session.getMapper(UserMapper.class); for (int i 0; i users.size(); i) { mapper.insert(users.get(i)); if (i % 1000 0) { session.commit(); } } session.commit(); } finally { session.close(); } }7.2 二级缓存Mapper CacheNamespace(size 512) // 开启二级缓存 public interface UserMapper extends BaseMapperUser { } // 或在 XML 中配置 /* mapper namespacecom.example.mapper.UserMapper cache evictionLRU flushInterval60000 size512 readOnlytrue/ /mapper */八、常见问题❌ 问题1Invalid bound statement (not found)原因Mapper XML 文件未被扫描到解决mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml❌ 问题2逻辑删除不生效原因字段类型不匹配或配置错误解决TableLogic private Integer deleted; // 必须是 Integer不能是 int❌ 问题3分页查询返回总条数为 0原因未配置分页插件解决添加 PaginationInnerInterceptor❌ 问题4批量插入速度慢解决使用 saveBatch 或手动控制 SqlSession九、总结MyBatis-Plus 特性速查表特性实现方式基础 CRUD继承 BaseMapper / IService分页查询PaginationInnerInterceptor代码生成FastAutoGenerator逻辑删除TableLogic自动填充MetaObjectHandler乐观锁Version OptimisticLockerInnerInterceptor多租户TenantLineInnerInterceptor动态表名DynamicTableNameInnerInterceptor觉得有用的话点个赞收藏关注我每周持续更新实战教程标签java | mybatis-plus | springboot | 后端 | orm