🚀MyBatis-Plus 从入门到精通:CRUD、条件构造器、分页、多表联查、性能优化

摘要:MyBatis-Plus 是国内 Java 开发者的 ORM 框架首选,被誉为"开发效率神器"。本文基于 2026 最新版,从快速入门到高级应用,全面讲解 CRUD、条件构造器、分页插件、多表查询和性能优化等核心知识点。通俗易懂,简洁明了,助你快速掌握企业级开发必备技能!


在这里插入图片描述

一、 为什么选择 MyBatis-Plus?

🚀 核心优势

特性 MyBatis MyBatis-Plus
基础 CRUD 需手写 SQL 内置通用 Mapper,零 SQL
条件构造 手动拼接 WHERE LambdaQueryWrapper,类型安全
分页支持 需配置插件 内置分页插件,开箱即用
代码生成 内置代码生成器,一键生成
性能分析 内置性能分析插件
学习成本 中等 低(兼容 MyBatis)

核心理念只做增强,不做改变。完全兼容 MyBatis,引入 MP 后原有代码无需修改。


二、 快速入门:5 分钟上手

1. 引入依赖(2026 最新版)

<dependencies>
    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- MyBatis-Plus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        <version>3.5.9</version>
    </dependency>
    
    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- Lombok(简化实体类) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

⚠️ 注意:Spring Boot 3.x 使用 mybatis-plus-spring-boot3-starter,Spring Boot 2.x 使用 mybatis-plus-boot-starter

2. 配置数据源

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

# MyBatis-Plus 配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 打印 SQL 日志
  global-config:
    db-config:
      id-type: auto  # 主键自增
      logic-delete-field: deleted  # 全局逻辑删除字段
      logic-delete-value: 1  # 已删除
      logic-not-delete-value: 0  # 未删除

3. 创建实体类

@Data
@TableName("user")  // 指定表名
public class User {
    
    @TableId(type = IdType.AUTO)  // 主键自增
    private Long id;
    
    private String name;
    
    private Integer age;
    
    private String email;
    
    @TableField(fill = FieldFill.INSERT)  // 插入时自动填充
    private LocalDateTime createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)  // 插入和更新时自动填充
    private LocalDateTime updateTime;
    
    @TableLogic  // 逻辑删除
    private Integer deleted;
}

4. 创建 Mapper 接口

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 继承 BaseMapper 后,自动拥有 CRUD 方法,无需编写 XML
}

5. 启动类添加注解

@SpringBootApplication
@MapperScan("com.example.demo.mapper")  // 扫描 Mapper 接口
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

6. 测试 CRUD

@SpringBootTest
class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    // ✅ 插入
    @Test
    void insert() {
        User user = new User();
        user.setName("张三");
        user.setAge(25);
        user.setEmail("zhangsan@example.com");
        
        int rows = userMapper.insert(user);
        System.out.println("影响行数: " + rows);
        System.out.println("生成的ID: " + user.getId());
    }

    // ✅ 查询单个
    @Test
    void selectById() {
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }

    // ✅ 更新
    @Test
    void updateById() {
        User user = new User();
        user.setId(1L);
        user.setAge(26);
        
        int rows = userMapper.updateById(user);
        System.out.println("影响行数: " + rows);
    }

    // ✅ 删除
    @Test
    void deleteById() {
        int rows = userMapper.deleteById(1L);
        System.out.println("影响行数: " + rows);
    }
}

三、 常用注解详解

1. 实体类注解

注解 作用 示例
@TableName 指定表名 @TableName("sys_user")
@TableId 指定主键 @TableId(type = IdType.ASSIGN_ID)
@TableField 指定字段 @TableField("user_name")
@TableLogic 逻辑删除 @TableLogic
@Version 乐观锁 @Version

2. 主键策略

@TableId(type = IdType.AUTO)          // 数据库自增
@TableId(type = IdType.ASSIGN_ID)     // 雪花算法(默认)
@TableId(type = IdType.ASSIGN_UUID)   // UUID
@TableId(type = IdType.INPUT)         // 手动输入

3. 自动填充

@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());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

4. 字段忽略与加密

@TableField(exist = false)  // 非表字段
private String confirmPassword;

@TableField(select = false)  // 查询时不返回
private String password;

@TableField(typeHandler = EncryptTypeHandler.class)  // 自定义类型处理器(加密)
private String idCard;

四、 条件构造器:强大且灵活

MyBatis-Plus 的核心武器,告别手写 SQL WHERE 子句。

1. QueryWrapper(基础用法)

@Test
void testQueryWrapper() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    
    wrapper.eq("age", 25)                    // age = 25
           .like("name", "张")               // name LIKE '%张%'
           .between("age", 20, 30)           // age BETWEEN 20 AND 30
           .orderByDesc("create_time");      // ORDER BY create_time DESC
    
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

2. LambdaQueryWrapper(推荐⭐)

类型安全,重构友好,避免硬编码字段名。

@Test
void testLambdaQueryWrapper() {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    
    wrapper.eq(User::getAge, 25)                    // age = 25
           .like(User::getName, "张")               // name LIKE '%张%'
           .between(User::getAge, 20, 30)           // age BETWEEN 20 AND 30
           .orderByDesc(User::getCreateTime);       // ORDER BY create_time DESC
    
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

3. 常用条件方法

方法 SQL 等价 示例
eq = .eq(User::getAge, 25)
ne != .ne(User::getStatus, 0)
gt > .gt(User::getAge, 18)
ge >= .ge(User::getAge, 18)
lt < .lt(User::getAge, 60)
le <= .le(User::getAge, 60)
like LIKE '%值%' .like(User::getName, "张")
likeRight LIKE '值%' .likeRight(User::getName, "张")
in IN .in(User::getId, 1, 2, 3)
notIn NOT IN .notIn(User::getId, 1, 2, 3)
between BETWEEN .between(User::getAge, 20, 30)
isNull IS NULL .isNull(User::getEmail)
isNotNull IS NOT NULL .isNotNull(User::getEmail)
groupBy GROUP BY .groupBy(User::getAge)
orderByAsc ORDER BY ASC .orderByAsc(User::getAge)
orderByDesc ORDER BY DESC .orderByDesc(User::getCreateTime)

4. 动态条件查询

@Test
void testDynamicQuery() {
    String name = "张";
    Integer minAge = 20;
    Integer maxAge = 30;
    
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    
    // ✅ 条件为真时才拼接
    wrapper.like(StringUtils.isNotBlank(name), User::getName, name)
           .ge(minAge != null, User::getAge, minAge)
           .le(maxAge != null, User::getAge, maxAge)
           .orderByDesc(User::getCreateTime);
    
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

5. 复杂条件组合

@Test
void testComplexQuery() {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    
    // (age > 20 OR email IS NOT NULL) AND name LIKE '%张%'
    wrapper.and(w -> w.gt(User::getAge, 20)
                      .or()
                      .isNotNull(User::getEmail))
           .like(User::getName, "张");
    
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

6. UpdateWrapper(条件更新)

@Test
void testUpdateWrapper() {
    LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
    
    wrapper.eq(User::getAge, 25)
           .set(User::getAge, 26)
           .set(User::getEmail, "newemail@example.com");
    
    int rows = userMapper.update(null, wrapper);
    System.out.println("影响行数: " + rows);
}

五、 分页插件:开箱即用

1. 配置分页插件

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 添加分页插件
        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInterceptor.setMaxLimit(500L);  // 单页最大限制条数
        paginationInterceptor.setOverflow(false);  // 溢出总页数后是否处理
        
        interceptor.addInnerInterceptor(paginationInterceptor);
        
        return interceptor;
    }
}

2. 基础分页查询

@Test
void testPage() {
    // 当前页: 1, 每页大小: 10
    Page<User> page = new Page<>(1, 10);
    
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    wrapper.ge(User::getAge, 20)
           .orderByDesc(User::getCreateTime);
    
    Page<User> result = userMapper.selectPage(page, wrapper);
    
    System.out.println("总记录数: " + result.getTotal());
    System.out.println("总页数: " + result.getPages());
    System.out.println("当前页: " + result.getCurrent());
    System.out.println("每页大小: " + result.getSize());
    System.out.println("数据列表: " + result.getRecords());
}

3. 封装分页响应

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult<T> {
    private Long total;        // 总记录数
    private Long pages;        // 总页数
    private Long current;      // 当前页
    private Long size;         // 每页大小
    private List<T> records;   // 数据列表

    public static <T> PageResult<T> of(Page<T> page) {
        return new PageResult<>(
            page.getTotal(),
            page.getPages(),
            page.getCurrent(),
            page.getSize(),
            page.getRecords()
        );
    }
}

4. Service 层分页

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public PageResult<User> getUserPage(Integer pageNum, Integer pageSize, String name) {
        Page<User> page = new Page<>(pageNum, pageSize);
        
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(name), User::getName, name)
               .orderByDesc(User::getCreateTime);
        
        Page<User> result = this.page(page, wrapper);
        
        return PageResult.of(result);
    }
}

5. Controller 层调用

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/page")
    public Result<PageResult<User>> getUserPage(
            @RequestParam(defaultValue = "1") Integer pageNum,
            @RequestParam(defaultValue = "10") Integer pageSize,
            @RequestParam(required = false) String name) {
        
        PageResult<User> result = userService.getUserPage(pageNum, pageSize, name);
        
        return Result.success(result);
    }
}

六、 多表查询:灵活应对复杂场景

虽然 MyBatis-Plus 主打单表操作,但多表查询依然可以通过以下方式实现。

方案一:使用 @Select 注解(简单场景)

@Mapper
public interface OrderMapper extends BaseMapper<Order> {

    @Select("SELECT o.*, u.name AS user_name, u.email AS user_email " +
            "FROM orders o " +
            "LEFT JOIN user u ON o.user_id = u.id " +
            "WHERE o.id = #{orderId}")
    OrderWithUserVO selectOrderWithUser(@Param("orderId") Long orderId);
}

方案二:XML 映射文件(推荐⭐)

1. 创建 VO 类
@Data
public class OrderWithUserVO {
    private Long orderId;
    private String orderNo;
    private BigDecimal amount;
    private LocalDateTime orderTime;
    
    // 用户信息
    private Long userId;
    private String userName;
    private String userEmail;
}
2. 编写 XML
<!-- mapper/OrderMapper.xml -->
<?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">
<mapper namespace="com.example.demo.mapper.OrderMapper">

    <resultMap id="OrderWithUserMap" type="com.example.demo.vo.OrderWithUserVO">
        <id property="orderId" column="order_id"/>
        <result property="orderNo" column="order_no"/>
        <result property="amount" column="amount"/>
        <result property="orderTime" column="order_time"/>
        <result property="userId" column="user_id"/>
        <result property="userName" column="user_name"/>
        <result property="userEmail" column="user_email"/>
    </resultMap>

    <select id="selectOrderWithUser" resultMap="OrderWithUserMap">
        SELECT 
            o.id AS order_id,
            o.order_no,
            o.amount,
            o.order_time,
            u.id AS user_id,
            u.name AS user_name,
            u.email AS user_email
        FROM orders o
        LEFT JOIN user u ON o.user_id = u.id
        WHERE o.id = #{orderId}
    </select>

    <select id="selectOrderListWithUser" resultMap="OrderWithUserMap">
        SELECT 
            o.id AS order_id,
            o.order_no,
            o.amount,
            o.order_time,
            u.id AS user_id,
            u.name AS user_name,
            u.email AS user_email
        FROM orders o
        LEFT JOIN user u ON o.user_id = u.id
        <where>
            <if test="orderNo != null and orderNo != ''">
                AND o.order_no LIKE CONCAT('%', #{orderNo}, '%')
            </if>
            <if test="userName != null and userName != ''">
                AND u.name LIKE CONCAT('%', #{userName}, '%')
            </if>
        </where>
        ORDER BY o.order_time DESC
    </select>

</mapper>
3. Mapper 接口
@Mapper
public interface OrderMapper extends BaseMapper<Order> {

    OrderWithUserVO selectOrderWithUser(@Param("orderId") Long orderId);
    
    List<OrderWithUserVO> selectOrderListWithUser(
        @Param("orderNo") String orderNo, 
        @Param("userName") String userName
    );
}

方案三:多次查询 + 内存组装(高性能场景)

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private UserMapper userMapper;

    /**
     * 查询订单列表并关联用户信息
     * 性能优于 JOIN,适合大数据量场景
     */
    public List<OrderWithUserVO> getOrderListWithUser() {
        // 1. 查询订单列表
        List<Order> orders = orderMapper.selectList(null);
        
        if (orders.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 2. 提取所有用户ID
        List<Long> userIds = orders.stream()
                .map(Order::getUserId)
                .distinct()
                .collect(Collectors.toList());
        
        // 3. 批量查询用户信息
        List<User> users = userMapper.selectBatchIds(userIds);
        Map<Long, User> userMap = users.stream()
                .collect(Collectors.toMap(User::getId, Function.identity()));
        
        // 4. 内存组装
        return orders.stream().map(order -> {
            OrderWithUserVO vo = new OrderWithUserVO();
            BeanUtils.copyProperties(order, vo);
            
            User user = userMap.get(order.getUserId());
            if (user != null) {
                vo.setUserName(user.getName());
                vo.setUserEmail(user.getEmail());
            }
            
            return vo;
        }).collect(Collectors.toList());
    }
}

性能对比:

  • JOIN 查询:1 次 SQL,但数据冗余大,网络传输量大。
  • 多次查询:N+1 次 SQL,但可通过批量查询优化,适合缓存场景。

七、 性能优化:让查询飞起来

1. 开启 SQL 日志(开发环境)

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2. 防止全表更新与删除

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 防止全表更新与删除
        BlockAttackInnerInterceptor blockAttackInterceptor = new BlockAttackInnerInterceptor();
        interceptor.addInnerInterceptor(blockAttackInterceptor);
        
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        
        return interceptor;
    }
}

执行 UPDATE user SET age = 20 时会抛出异常,必须加 WHERE 条件。

3. 使用索引优化

@Test
void testIndexOptimization() {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    
    // ✅ 走索引:等值查询
    wrapper.eq(User::getEmail, "test@example.com");
    
    // ✅ 走索引:左模糊查询
    wrapper.likeRight(User::getName, "张");  // LIKE '张%'
    
    // ❌ 不走索引:右模糊查询
    wrapper.likeLeft(User::getName, "三");  // LIKE '%三'
    
    // ❌ 不走索引:函数包裹字段
    // YEAR(create_time) = 2024
    
    List<User> users = userMapper.selectList(wrapper);
}

4. 只查询需要的字段

@Test
void testSelectFields() {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    wrapper.select(User::getId, User::getName, User::getEmail)  // 只查询指定字段
           .eq(User::getAge, 25);
    
    List<User> users = userMapper.selectList(wrapper);
}

生成的 SQL:

SELECT id, name, email FROM user WHERE age = 25

5. 批量操作

@Test
void testBatchInsert() {
    List<User> userList = new ArrayList<>();
    
    for (int i = 0; i < 1000; i++) {
        User user = new User();
        user.setName("用户" + i);
        user.setAge(20 + i % 10);
        user.setEmail("user" + i + "@example.com");
        userList.add(user);
    }
    
    // ✅ 批量插入(默认 1000 条一批)
    boolean success = userService.saveBatch(userList);
    System.out.println("批量插入结果: " + success);
}

6. 缓存优化

一级缓存(默认开启)

同一 SqlSession 内,相同查询直接从缓存读取。

二级缓存(谨慎使用)
mybatis-plus:
  configuration:
    cache-enabled: true  # 开启二级缓存
@CacheNamespace
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

⚠️ 注意:分布式环境下不建议使用二级缓存,推荐使用 Redis。

7. 慢查询监控

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 性能分析插件(仅开发环境)
        PerformanceInnerInterceptor performanceInterceptor = new PerformanceInnerInterceptor();
        performanceInterceptor.setMaxTime(1000L);  // 最大执行时间 1000ms
        performanceInterceptor.setFormat(true);    // 格式化 SQL
        
        interceptor.addInnerInterceptor(performanceInterceptor);
        
        return interceptor;
    }
}

超过 1000ms 的 SQL 会抛出异常,帮助定位慢查询。


八、 高级特性

1. 乐观锁

@Data
@TableName("product")
public class Product {
    
    @TableId
    private Long id;
    
    private String name;
    
    private Integer stock;
    
    @Version  // 乐观锁版本号
    private Integer version;
}
@Test
void testOptimisticLocker() {
    // 1. 查询商品
    Product product = productMapper.selectById(1L);
    System.out.println("版本号: " + product.getVersion());
    
    // 2. 修改库存
    product.setStock(product.getStock() - 1);
    
    // 3. 更新(自动携带版本号条件)
    int rows = productMapper.updateById(product);
    System.out.println("影响行数: " + rows);  // 成功返回 1,失败返回 0
}

生成的 SQL:

UPDATE product SET stock = 99, version = 2 
WHERE id = 1 AND version = 1

2. 逻辑删除

@Data
@TableName("user")
public class User {
    
    @TableId
    private Long id;
    
    private String name;
    
    @TableLogic  // 逻辑删除字段
    private Integer deleted;
}
@Test
void testLogicDelete() {
    // 删除(实际是更新 deleted = 1)
    int rows = userMapper.deleteById(1L);
    System.out.println("影响行数: " + rows);
    
    // 查询(自动添加 deleted = 0 条件)
    User user = userMapper.selectById(1L);  // 返回 null
}

生成的 SQL:

-- 删除
UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0

-- 查询
SELECT * FROM user WHERE id = 1 AND deleted = 0

3. 枚举自动转换

@Getter
public enum GenderEnum {
    MALE(1, "男"),
    FEMALE(2, "女"),
    UNKNOWN(0, "未知");

    @EnumValue  // 存入数据库的值
    private final Integer code;
    
    @JsonValue  // 返回给前端的值
    private final String desc;

    GenderEnum(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }
}
@Data
@TableName("user")
public class User {
    
    @TableId
    private Long id;
    
    private String name;
    
    private GenderEnum gender;  // 自动转换
}

4. 代码生成器

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.9</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
</dependency>
public class CodeGenerator {

    public static void main(String[] args) {
        FastAutoGenerator.create(
            "jdbc:mysql://localhost:3306/mp_demo",
            "root",
            "123456"
        )
        .globalConfig(builder -> {
            builder.author("YourName")           // 作者
                   .outputDir("src/main/java")   // 输出目录
                   .commentDate("yyyy-MM-dd");   // 注释日期格式
        })
        .packageConfig(builder -> {
            builder.parent("com.example.demo")   // 父包名
                   .moduleName("system")         // 模块名
                   .entity("entity")
                   .mapper("mapper")
                   .service("service")
                   .controller("controller");
        })
        .strategyConfig(builder -> {
            builder.addInclude("user", "order", "product")  // 需要生成的表
                   .addTablePrefix("t_", "sys_");           // 过滤表前缀
        })
        .templateEngine(new FreemarkerTemplateEngine())
        .execute();
    }
}

一键生成 Entity、Mapper、Service、Controller,开发效率提升 10 倍!


九、 最佳实践总结

✅ 推荐做法

  1. 优先使用 LambdaQueryWrapper:类型安全,重构友好。
  2. 单表操作用 MP,多表查询用 XML:发挥各自优势。
  3. 开启逻辑删除:避免误删数据,便于数据恢复。
  4. 使用乐观锁:高并发场景下保证数据一致性。
  5. 批量操作用 saveBatch/updateBatchById:减少数据库交互次数。
  6. 只查询需要的字段:减少网络传输,提升性能。
  7. 生产环境关闭 SQL 日志:避免性能损耗和信息泄露。

❌ 避免做法

  1. 不要滥用 JOIN:大数据量场景考虑多次查询 + 内存组装。
  2. 不要使用右模糊查询LIKE '%值' 不走索引。
  3. 不要在循环中查询数据库:改为批量查询。
  4. 不要滥用二级缓存:分布式环境下使用 Redis。
  5. 不要忘记加 WHERE 条件:开启防全表更新插件。

十、 总结

MyBatis-Plus 作为 ORM 框架的首选,凭借开发效率高、学习成本低、功能强大等优势,成为企业必用的技术栈。

核心知识点回顾:

  1. 快速入门:5 分钟上手,继承 BaseMapper 即可拥有 CRUD。
  2. 常用注解@TableName@TableId@TableField@TableLogic@Version
  3. 条件构造器:LambdaQueryWrapper 类型安全,动态条件灵活拼接。
  4. 分页插件:开箱即用,支持多种数据库。
  5. 多表查询:XML 映射文件 + 多次查询 + 内存组装。
  6. 性能优化:索引优化、字段裁剪、批量操作、缓存策略。

🌟 最后的话:工具的价值在于提升效率,但前提是理解其原理。掌握 MyBatis-Plus 的核心机制,才能在实际项目中游刃有余。


如果你觉得这篇文章对你有帮助,欢迎点赞👍、收藏⭐、评论💬,你的支持是我创作的最大动力!

#MyBatis-Plus #ORM框架 #Java开发 #SpringBoot #后端开发 #开发效率

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐