最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis-Plus從基礎(chǔ)CRUD到高級查詢與性能優(yōu)化實(shí)戰(zhàn)指南

 更新時(shí)間:2026年02月04日 11:22:28   作者:lbb 小魔仙  
MyBatis-Plus 與 Spring Boot 的集成非常簡潔,只需完成 Maven 依賴引入和基礎(chǔ)配置,即可快速啟用所有核心功能,本文將從環(huán)境搭建到性能優(yōu)化,系統(tǒng)化講解MyBatis-Plus的實(shí)戰(zhàn)用法,助力開發(fā)者快速上手并靈活運(yùn)用,感興趣的朋友跟隨小編一起看看吧

MyBatis-Plus 系統(tǒng)化實(shí)戰(zhàn):從基礎(chǔ) CRUD 到高級查詢與性能優(yōu)化

一、引言

在 Java 持久層開發(fā)領(lǐng)域,MyBatis 憑借其輕量、靈活、SQL 可控性強(qiáng)的特點(diǎn),成為企業(yè)級項(xiàng)目的主流選擇。但原生 MyBatis 存在大量重復(fù)編碼工作——例如基礎(chǔ) CRUD 接口的編寫、復(fù)雜查詢條件的拼接、分頁邏輯的重復(fù)實(shí)現(xiàn)等,這些冗余操作不僅降低開發(fā)效率,還可能因人為疏忽引入潛在 Bug。

MyBatis-Plus(簡稱 MP)作為 MyBatis 的增強(qiáng)工具,遵循“只做增強(qiáng),不做改變”的核心理念,在完全兼容 MyBatis 原有功能的基礎(chǔ)上,內(nèi)置了大量實(shí)用特性,徹底解決了原生 MyBatis 的痛點(diǎn)。其核心優(yōu)勢包括:無侵入式增強(qiáng)、內(nèi)置基礎(chǔ) CRUD 接口無需手動(dòng)編寫 SQL、強(qiáng)大的條件構(gòu)造器簡化查詢邏輯、完善的分頁插件與批量操作支持、靈活的關(guān)聯(lián)查詢方案等。

在企業(yè)開發(fā)中,MyBatis-Plus 能夠顯著提升持久層開發(fā)效率(減少 60% 以上的重復(fù)編碼),同時(shí)保證 SQL 的靈活性與性能可控性,廣泛應(yīng)用于中大型 Spring Boot 項(xiàng)目中,是 Java 開發(fā)者必備的實(shí)戰(zhàn)技能之一。本文將從環(huán)境搭建到性能優(yōu)化,系統(tǒng)化講解 MyBatis-Plus 的實(shí)戰(zhàn)用法,助力開發(fā)者快速上手并靈活運(yùn)用。

二、環(huán)境搭建:Spring Boot + MyBatis-Plus 快速集成

MyBatis-Plus 與 Spring Boot 的集成非常簡潔,只需完成 Maven 依賴引入和基礎(chǔ)配置,即可快速啟用所有核心功能。以下是完整的搭建步驟(基于 Spring Boot 2.7.x,JDK 8+)。

2.1 引入 Maven 依賴

在 pom.xml 中引入 MyBatis-Plus 核心依賴、數(shù)據(jù)庫驅(qū)動(dòng)(以 MySQL 8.0 為例)、 lombok(簡化實(shí)體類編寫),無需額外引入 MyBatis 依賴(MP 已內(nèi)置)。

<!-- Spring Boot 父依賴 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.15</version>
    <relativePath/>
</parent>
<dependencies>
    <!-- Spring Boot Web 依賴(非必需,用于演示接口調(diào)用) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- MyBatis-Plus 核心依賴 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    <!-- MySQL 驅(qū)動(dòng) -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- lombok 簡化實(shí)體類 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!-- 測試依賴 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2.2 核心配置(application.yml)

在 resources 目錄下創(chuàng)建 application.yml 文件,配置數(shù)據(jù)庫連接信息、MyBatis-Plus 基礎(chǔ)參數(shù)(如 mapper 映射文件路徑、實(shí)體類別名包、SQL 日志打印等),配置后即可自動(dòng)加載。

spring:
  # 數(shù)據(jù)庫配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false
    username: root  # 替換為你的數(shù)據(jù)庫用戶名
    password: 123456  # 替換為你的數(shù)據(jù)庫密碼
# MyBatis-Plus 配置
mybatis-plus:
  # mapper 映射文件路徑(若無需自定義 SQL,可省略)
  mapper-locations: classpath:mapper/**/*.xml
  # 實(shí)體類別名包(簡化 XML 中實(shí)體類引用)
  type-aliases-package: com.example.mpdemo.entity
  # 全局配置
  global-config:
    db-config:
      # 主鍵生成策略(AUTO=自增,NONE=手動(dòng)輸入,ASSIGN_ID=雪花算法等)
      id-type: AUTO
      # 邏輯刪除字段配置(可選,用于軟刪除)
      logic-delete-field: isDeleted
      logic-delete-value: 1  # 已刪除
      logic-not-delete-value: 0  # 未刪除
  # 日志配置(打印執(zhí)行的 SQL,便于調(diào)試)
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.3 啟動(dòng)類配置

在 Spring Boot 啟動(dòng)類上添加 @MapperScan 注解,指定 Mapper 接口所在的包路徑,確保 MyBatis-Plus 能夠掃描到 Mapper 接口并生成代理對象。

package com.example.mpdemo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 掃描 Mapper 接口所在包
@MapperScan("com.example.mpdemo.mapper")
@SpringBootApplication
public class MpDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MpDemoApplication.class, args);
    }
}

三、基礎(chǔ) CRUD 實(shí)戰(zhàn):基于 IService 與 BaseMapper

MyBatis-Plus 提供了兩個(gè)核心接口用于實(shí)現(xiàn)基礎(chǔ) CRUD 操作:BaseMapper(面向 Mapper 層)和 IService(面向 Service 層,封裝了 BaseMapper 的方法,提供更便捷的調(diào)用)。推薦在開發(fā)中使用 IService + ServiceImpl 的組合,簡化 Service 層代碼編寫。

以下將以 User 實(shí)體類為例,演示完整的基礎(chǔ) CRUD 實(shí)戰(zhàn)(包含實(shí)體類、Mapper 接口、Service 接口/實(shí)現(xiàn)類、調(diào)用示例),所有代碼可直接復(fù)制運(yùn)行。

3.1 準(zhǔn)備數(shù)據(jù)庫表

創(chuàng)建 user 表(對應(yīng) User 實(shí)體類),SQL 語句如下(適配 MySQL 8.0,包含邏輯刪除字段):

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `username` varchar(50) NOT NULL COMMENT '用戶名',
  `password` varchar(100) NOT NULL COMMENT '密碼(實(shí)際開發(fā)中需加密)',
  `age` int(3) DEFAULT NULL COMMENT '年齡',
  `email` varchar(100) DEFAULT NULL COMMENT '郵箱',
  `is_deleted` tinyint(1) DEFAULT 0 COMMENT '邏輯刪除(0=未刪除,1=已刪除)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用戶表';

3.2 編寫實(shí)體類 User

使用 lombok 的 @Data 注解簡化 getter/setter 方法,通過 MyBatis-Plus 的注解指定表名、字段映射、備注等信息。

package com.example.mpdemo.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;
@Data
@TableName("user")  // 指定對應(yīng)數(shù)據(jù)庫表名(若實(shí)體類名與表名一致,可省略)
public class User {
    // 主鍵,自增(對應(yīng)全局配置的 id-type: AUTO)
    @TableId(type = IdType.AUTO)
    private Integer id;
    // 用戶名(非空字段)
    @TableField("username")  // 若實(shí)體類字段與表字段一致,可省略
    private String username;
    // 密碼
    private String password;
    // 年齡
    private Integer age;
    // 郵箱
    private String email;
    // 邏輯刪除字段(與全局配置一致,可省略注解)
    @TableLogic
    private Integer isDeleted;
    // 創(chuàng)建時(shí)間(自動(dòng)填充)
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    // 更新時(shí)間(自動(dòng)填充)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}

3.3 自動(dòng)填充配置(可選)

上述實(shí)體類中,createTime 和 updateTime 字段使用了 @TableField(fill = …) 注解,用于實(shí)現(xiàn)“插入時(shí)自動(dòng)填充創(chuàng)建時(shí)間、更新時(shí)自動(dòng)填充更新時(shí)間”,無需手動(dòng)設(shè)置。需創(chuàng)建填充處理器:

package com.example.mpdemo.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    // 插入時(shí)填充
    @Override
    public void insertFill(MetaObject metaObject) {
        // 填充 createTime 和 updateTime
        strictInsertFill(metaObject, "createTime", Date.class, new Date());
        strictInsertFill(metaObject, "updateTime", Date.class, new Date());
    }
    // 更新時(shí)填充
    @Override
    public void updateFill(MetaObject metaObject) {
        // 只填充 updateTime
        strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }
}

3.4 編寫 Mapper 接口

UserMapper 繼承 BaseMapper,BaseMapper 已內(nèi)置了 selectById、insert、updateById、deleteById 等基礎(chǔ) CRUD 方法,無需手動(dòng)編寫任何方法。

package com.example.mpdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
import org.springframework.stereotype.Repository;
// @Repository 用于標(biāo)識(shí) Mapper 接口,避免 IDE 報(bào)錯(cuò)(可選)
@Repository
public interface UserMapper extends BaseMapper<User> {
    // 無需編寫任何方法,BaseMapper 已提供所有基礎(chǔ) CRUD 操作
}

3.5 編寫 Service 接口與實(shí)現(xiàn)類

IService 是 MyBatis-Plus 提供的 Service 層接口,封裝了 BaseMapper 的方法,還提供了批量操作、條件查詢等便捷方法。UserService 繼承 IService,UserServiceImpl 繼承 ServiceImpl(實(shí)現(xiàn) IService)并注入 UserMapper。

3.5.1 Service 接口

package com.example.mpdemo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mpdemo.entity.User;
// 繼承 IService,指定實(shí)體類類型
public interface UserService extends IService<User> {
    // 可添加自定義 Service 方法(基礎(chǔ) CRUD 無需添加)
}

3.5.2 Service 實(shí)現(xiàn)類

package com.example.mpdemo.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import com.example.mpdemo.service.UserService;
import org.springframework.stereotype.Service;
// 繼承 ServiceImpl,注入 Mapper 接口,實(shí)現(xiàn) Service 接口
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    // 基礎(chǔ) CRUD 方法無需實(shí)現(xiàn),ServiceImpl 已全部封裝
}

3.6 基礎(chǔ) CRUD 調(diào)用示例(測試類)

通過 Spring Boot 測試類,演示 IService 中常用的基礎(chǔ) CRUD 方法,運(yùn)行測試方法即可驗(yàn)證效果。

package com.example.mpdemo;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class UserServiceTest {
    // 注入 UserService
    @Autowired
    private UserService userService;
    // 1. 新增用戶(insert)
    @Test
    public void testInsert() {
        User user = new User();
        user.setUsername("zhangsan");
        user.setPassword("123456");
        user.setAge(20);
        user.setEmail("zhangsan@example.com");
        // 調(diào)用 IService 的 save 方法(底層調(diào)用 BaseMapper 的 insert)
        boolean success = userService.save(user);
        System.out.println("新增結(jié)果:" + success + ",新增用戶ID:" + user.getId());
    }
    // 2. 根據(jù)ID查詢用戶(selectById)
    @Test
    public void testSelectById() {
        User user = userService.getById(1); // 查詢ID為1的用戶
        System.out.println("查詢到的用戶:" + user);
    }
    // 3. 查詢所有用戶(selectList)
    @Test
    public void testSelectAll() {
        List<User> userList = userService.list(); // 查詢所有未刪除的用戶(自動(dòng)過濾邏輯刪除)
        userList.forEach(System.out::println);
    }
    // 4. 根據(jù)ID更新用戶(updateById)
    @Test
    public void testUpdateById() {
        User user = new User();
        user.setId(1); // 必須設(shè)置主鍵ID
        user.setAge(22); // 更新年齡為22
        user.setEmail("zhangsan22@example.com"); // 更新郵箱
        boolean success = userService.updateById(user);
        System.out.println("更新結(jié)果:" + success);
    }
    // 5. 根據(jù)ID刪除用戶(邏輯刪除,deleteById)
    @Test
    public void testDeleteById() {
        boolean success = userService.removeById(1); // 邏輯刪除ID為1的用戶
        System.out.println("刪除結(jié)果:" + success);
    }
    // 6. 批量新增(saveBatch)
    @Test
    public void testSaveBatch() {
        List<User> userList = List.of(
                new User(null, "lisi", "123456", 25, "lisi@example.com", 0, null, null),
                new User(null, "wangwu", "123456", 28, "wangwu@example.com", 0, null, null)
        );
        // 批量新增,底層會(huì)分批次執(zhí)行SQL(默認(rèn)批次大小1000)
        boolean success = userService.saveBatch(userList);
        System.out.println("批量新增結(jié)果:" + success);
    }
}

四、高級查詢技巧:提升查詢靈活性與效率

基礎(chǔ) CRUD 僅能滿足簡單的業(yè)務(wù)需求,在實(shí)際開發(fā)中,往往需要復(fù)雜的查詢條件(如多字段模糊查詢、范圍查詢)、分頁查詢、關(guān)聯(lián)查詢等。MyBatis-Plus 提供了完善的高級查詢特性,以下講解最常用、最實(shí)用的技巧。

4.1 條件構(gòu)造器:QueryWrapper / LambdaQueryWrapper

條件構(gòu)造器是 MyBatis-Plus 高級查詢的核心,用于動(dòng)態(tài)拼接 SQL 查詢條件(無需手動(dòng)拼接 SQL 字符串,避免 SQL 注入風(fēng)險(xiǎn))。常用的構(gòu)造器有兩個(gè):

  • QueryWrapper:通過字符串指定字段名,靈活性高,但字段名容易寫錯(cuò)(無編譯期檢查);
  • LambdaQueryWrapper:通過 Lambda 表達(dá)式獲取字段名,有編譯期檢查,避免字段名寫錯(cuò),推薦使用。

以下通過示例演示兩種構(gòu)造器的常用用法(基于 UserService):

package com.example.mpdemo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class QueryWrapperTest {
    @Autowired
    private UserService userService;
    // 1. QueryWrapper 示例:多條件查詢(年齡大于20,郵箱包含example,用戶名不為null)
    @Test
    public void testQueryWrapper() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 年齡 > 20
        queryWrapper.gt("age", 20);
        // 郵箱 like %example%
        queryWrapper.like("email", "example");
        // 用戶名 is not null
        queryWrapper.isNotNull("username");
        // 排序:按年齡降序,按ID升序
        queryWrapper.orderByDesc("age").orderByAsc("id");
        List<User> userList = userService.list(queryWrapper);
        userList.forEach(System.out::println);
    }
    // 2. LambdaQueryWrapper 示例(推薦):同樣的條件,避免字段名寫錯(cuò)
    @Test
    public void testLambdaQueryWrapper() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 年齡 > 20(Lambda表達(dá)式獲取字段,編譯期檢查)
        lambdaQueryWrapper.gt(User::getAge, 20);
        // 郵箱 like %example%
        lambdaQueryWrapper.like(User::getEmail, "example");
        // 用戶名 is not null
        lambdaQueryWrapper.isNotNull(User::getUsername);
        // 排序:按年齡降序,按ID升序
        lambdaQueryWrapper.orderByDesc(User::getAge).orderByAsc(User::getId);
        List<User> userList = userService.list(lambdaQueryWrapper);
        userList.forEach(System.out::println);
    }
    // 3. 條件構(gòu)造器常用方法補(bǔ)充
    @Test
    public void testLambdaQueryWrapperAdvanced() {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        // 1. 范圍查詢:年齡在20-30之間(包含20和30)
        wrapper.between(User::getAge, 20, 30);
        // 2. 等值查詢:用戶名 = zhangsan
        wrapper.eq(User::getUsername, "zhangsan");
        // 3. 非等值查詢:密碼 != 123456
        wrapper.ne(User::getPassword, "123456");
        // 4. 模糊查詢:用戶名以zhang開頭(like 'zhang%')
        wrapper.likeLeft(User::getUsername, "zhang");
        // 5. 模糊查詢:用戶名以san結(jié)尾(like '%san')
        wrapper.likeRight(User::getUsername, "san");
        // 6. 空值查詢:郵箱 is null
        wrapper.isNull(User::getEmail);
        // 7. 非空查詢:郵箱 is not null
        wrapper.isNotNull(User::getEmail);
        // 8. 邏輯或:年齡 < 20 或 年齡 > 30
        wrapper.or().lt(User::getAge, 20).or().gt(User::getAge, 30);
        // 9. 邏輯與(默認(rèn),可省略):年齡 > 20 且 郵箱不為空
        wrapper.and(i -> i.gt(User::getAge, 20).isNotNull(User::getEmail));
        // 10. 只查詢指定字段(避免查詢無用字段,提升性能)
        wrapper.select(User::getId, User::getUsername, User::getAge);
        List<User> userList = userService.list(wrapper);
        userList.forEach(System.out::println);
    }
}

4.2 分頁插件配置與調(diào)用示例

MyBatis-Plus 內(nèi)置了分頁插件(PaginationInnerInterceptor),支持 MySQL、Oracle、SQL Server 等多種數(shù)據(jù)庫,配置簡單,調(diào)用便捷,無需手動(dòng)編寫分頁 SQL(如 limit 語句)。

4.2.1 分頁插件配置

創(chuàng)建 MyBatis-Plus 配置類,注入分頁插件,指定數(shù)據(jù)庫類型(避免分頁語法兼容問題)。

package com.example.mpdemo.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
    // 配置分頁插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分頁插件,指定數(shù)據(jù)庫類型為 MySQL
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

4.2.2 分頁查詢調(diào)用示例

使用 Page 類封裝分頁參數(shù)(當(dāng)前頁碼、每頁條數(shù)),結(jié)合條件構(gòu)造器,調(diào)用 IService 的 page 方法即可實(shí)現(xiàn)分頁查詢,返回結(jié)果包含分頁信息(總條數(shù)、總頁數(shù)、當(dāng)前頁數(shù)據(jù)等)。

package com.example.mpdemo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class PageTest {
    @Autowired
    private UserService userService;
    // 1. 基礎(chǔ)分頁查詢(無條件)
    @Test
    public void testPageBasic() {
        // 分頁參數(shù):當(dāng)前頁(從1開始)、每頁條數(shù)
        Page<User> page = new Page<>(1, 2);
        // 調(diào)用 page 方法,返回分頁結(jié)果
        IPage<User> userIPage = userService.page(page);
        // 分頁信息解析
        System.out.println("總條數(shù):" + userIPage.getTotal());
        System.out.println("總頁數(shù):" + userIPage.getPages());
        System.out.println("當(dāng)前頁碼:" + userIPage.getCurrent());
        System.out.println("每頁條數(shù):" + userIPage.getSize());
        System.out.println("當(dāng)前頁數(shù)據(jù):");
        userIPage.getRecords().forEach(System.out::println);
    }
    // 2. 帶條件的分頁查詢(結(jié)合 LambdaQueryWrapper)
    @Test
    public void testPageWithCondition() {
        // 分頁參數(shù):第2頁,每頁3條
        Page<User> page = new Page<>(2, 3);
        // 條件:年齡 > 20,按年齡降序
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
                .gt(User::getAge, 20)
                .orderByDesc(User::getAge);
        // 帶條件分頁查詢
        IPage<User> userIPage = userService.page(page, wrapper);
        // 輸出分頁結(jié)果
        System.out.println("總條數(shù):" + userIPage.getTotal());
        System.out.println("總頁數(shù):" + userIPage.getPages());
        userIPage.getRecords().forEach(System.out::println);
    }
    // 3. 分頁查詢指定字段(避免查詢無用字段)
    @Test
    public void testPageSelectField() {
        Page<User> page = new Page<>(1, 2);
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
                .gt(User::getAge, 20)
                .select(User::getId, User::getUsername, User::getAge); // 只查詢3個(gè)字段
        IPage<User> userIPage = userService.page(page, wrapper);
        userIPage.getRecords().forEach(System.out::println);
    }
}

4.3 關(guān)聯(lián)查詢:注解與手動(dòng) SQL 最佳實(shí)踐

MyBatis-Plus 本身不直接提供像 MyBatis-Plus Join 那樣的強(qiáng)關(guān)聯(lián)查詢封裝,但可以通過 MyBatis 的原生注解(@One、@Many)或手動(dòng)編寫 XML SQL 實(shí)現(xiàn)關(guān)聯(lián)查詢(一對一、一對多),以下是企業(yè)開發(fā)中最常用的兩種方式。

示例場景:新增 Order 實(shí)體類(訂單表),User 與 Order 是一對多關(guān)系(一個(gè)用戶可以有多個(gè)訂單),演示一對多關(guān)聯(lián)查詢。

4.3.1 準(zhǔn)備關(guān)聯(lián)表與實(shí)體類

(1)訂單表 SQL
CREATE TABLE `order` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '訂單ID',
  `order_no` varchar(50) NOT NULL COMMENT '訂單編號(hào)',
  `user_id` int(11) NOT NULL COMMENT '關(guān)聯(lián)用戶ID(外鍵)',
  `total_amount` decimal(10,2) NOT NULL COMMENT '訂單總金額',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`) COMMENT '用戶ID索引,提升關(guān)聯(lián)查詢效率'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='訂單表';
(2)Order 實(shí)體類
package com.example.mpdemo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@TableName("`order`")  // 訂單表名是關(guān)鍵字order,需用反引號(hào)包裹
public class Order {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String orderNo;
    // 關(guān)聯(lián)用戶ID(外鍵)
    private Integer userId;
    private BigDecimal totalAmount;
    private Date createTime;
}
(3)修改 User 實(shí)體類(添加訂單列表屬性)
package com.example.mpdemo.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
@TableName("user")
public class User {
    // 原有字段不變,新增以下屬性
    // 一對多關(guān)聯(lián):一個(gè)用戶有多個(gè)訂單(非數(shù)據(jù)庫字段,需用@TableField(exist = false)標(biāo)識(shí))
    @TableField(exist = false)
    private List<Order> orderList;
}

4.3.2 方式一:通過 @One / @Many 注解實(shí)現(xiàn)關(guān)聯(lián)查詢

通過 MyBatis 的 @Many 注解(一對多),在 UserMapper 中編寫關(guān)聯(lián)查詢方法,無需編寫 XML 文件,適合簡單的關(guān)聯(lián)場景。

package com.example.mpdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.Order;
import com.example.mpdemo.entity.User;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserMapper extends BaseMapper<User> {
    // 一對多關(guān)聯(lián)查詢:查詢用戶及其所有訂單
    @Select("SELECT * FROM user WHERE id = #{userId}")
    @Results({
            // 映射用戶自身字段(id、username等)
            @Result(column = "id", property = "id"),
            @Result(column = "username", property = "username"),
            @Result(column = "age", property = "age"),
            @Result(column = "email", property = "email"),
            // 關(guān)聯(lián)查詢訂單:通過user的id關(guān)聯(lián)order的user_id
            @Result(
                    column = "id",  // 關(guān)聯(lián)字段(user的id)
                    property = "orderList",  // 映射到user的orderList屬性
                    // 一對多關(guān)聯(lián),使用@Many注解
                    many = @Many(select = "com.example.mpdemo.mapper.OrderMapper.selectByUserId")
            )
    })
    User selectUserWithOrders(Integer userId);
    // 批量查詢用戶及其訂單(可選)
    @Select("SELECT * FROM user WHERE id IN (#{ids})")
    @Results({
            @Result(column = "id", property = "id"),
            @Result(column = "username", property = "username"),
            @Result(
                    column = "id",
                    property = "orderList",
                    many = @Many(select = "com.example.mpdemo.mapper.OrderMapper.selectByUserId")
            )
    })
    List<User> selectUsersWithOrders(List<Integer> ids);
}
// 新增 OrderMapper 接口
package com.example.mpdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.Order;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface OrderMapper extends BaseMapper<Order> {
    // 根據(jù)用戶ID查詢訂單(供UserMapper的@Many注解調(diào)用)
    @Select("SELECT * FROM `order` WHERE user_id = #{userId}")
    List<Order> selectByUserId(Integer userId);
}

4.3.3 方式二:手動(dòng)編寫 XML SQL 實(shí)現(xiàn)關(guān)聯(lián)查詢(推薦)

對于復(fù)雜的關(guān)聯(lián)查詢(如多表關(guān)聯(lián)、多條件過濾),推薦使用 XML 編寫 SQL,靈活性更高,便于維護(hù)。以下演示通過 XML 實(shí)現(xiàn)用戶與訂單的一對多關(guān)聯(lián)查詢。

(1)修改 UserMapper 接口,添加關(guān)聯(lián)查詢方法
package com.example.mpdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserMapper extends BaseMapper<User> {
    // 新增:通過XML實(shí)現(xiàn)用戶與訂單的關(guān)聯(lián)查詢
    List<User> selectUserWithOrdersByXml(Integer userId);
}
(2)編寫 XML 映射文件

在 resources/mapper 目錄下創(chuàng)建 UserMapper.xml 文件(與 application.yml 中 mapper-locations 配置一致),編寫關(guān)聯(lián)查詢 SQL。

<?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.mpdemo.mapper.UserMapper"><!-- 一對多關(guān)聯(lián)查詢:查詢用戶及其所有訂單 -->
    <select id="selectUserWithOrdersByXml" resultMap="UserWithOrdersMap">
        SELECT
            u.id AS user_id,
            u.username,
            u.age,
            u.email,
            o.id AS order_id,
            o.order_no,
            o.total_amount,
            o.create_time AS order_create_time
        FROM
            user u
        LEFT JOIN
            `order` o ON u.id = o.user_id
        WHERE
            u.id = #{userId}
            AND u.is_deleted = 0
    </select><!-- 結(jié)果集映射:關(guān)聯(lián)用戶和訂單 -->
    <resultMap id="UserWithOrdersMap" type="com.example.mpdemo.entity.User">
        <!-- 用戶自身字段映射 -->
        <id column="user_id" property="id"/>
        <result column="username" property="username"/>
        <result column="age" property="age"/>
        <result column="email" property="email"/>
        <!-- 一對多關(guān)聯(lián):映射訂單列表 -->
        <collection property="orderList" ofType="com.example.mpdemo.entity.Order">
            <id column="order_id" property="id"/>
            <result column="order_no" property="orderNo"/>
            <result column="user_id" property="userId"/>
            <result column="total_amount" property="totalAmount"/>
            <result column="order_create_time" property="createTime"/>
        </collection>
    </resultMap>
</mapper>
(3)關(guān)聯(lián)查詢調(diào)用示例
package com.example.mpdemo;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class RelationQueryTest {
    @Autowired
    private UserMapper userMapper;
    // 測試注解方式關(guān)聯(lián)查詢
    @Test
    public void testSelectUserWithOrders() {
        User user = userMapper.selectUserWithOrders(1);
        System.out.println("用戶信息:" + user.getUsername() + "," + user.getEmail());
        System.out.println("用戶訂單:");
        user.getOrderList().forEach(order -> System.out.println(order.getOrderNo() + "," + order.getTotalAmount()));
    }
    // 測試XML方式關(guān)聯(lián)查詢
    @Test
    public void testSelectUserWithOrdersByXml() {
        User user = userMapper.selectUserWithOrdersByXml(1);
        System.out.println("用戶信息:" + user.getUsername() + "," + user.getEmail());
        System.out.println("用戶訂單:");
        user.getOrderList().forEach(order -> System.out.println(order.getOrderNo() + "," + order.getTotalAmount()));
    }
}

五、性能優(yōu)化策略:提升系統(tǒng)響應(yīng)速度與穩(wěn)定性

MyBatis-Plus 的高效性不僅體現(xiàn)在開發(fā)效率上,通過合理的配置與優(yōu)化,還能顯著提升系統(tǒng)的運(yùn)行性能。以下講解企業(yè)開發(fā)中最常用的 3 種性能優(yōu)化策略,涵蓋緩存、批量操作、SQL 日志分析。

5.1 二級緩存配置:減少數(shù)據(jù)庫查詢壓力

MyBatis 提供了兩級緩存:一級緩存(SqlSession 級緩存,默認(rèn)開啟)和二級緩存(Mapper 級緩存,默認(rèn)關(guān)閉)。MyBatis-Plus 完全兼容 MyBatis 的緩存機(jī)制,開啟二級緩存后,多個(gè) SqlSession 可以共享 Mapper 層的緩存數(shù)據(jù),減少重復(fù)查詢數(shù)據(jù)庫的次數(shù),提升查詢性能。

5.1.1 二級緩存開啟步驟

(1)全局開啟二級緩存(application.yml)
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    cache-enabled: true  # 全局開啟二級緩存(默認(rèn)false)
(2)在 Mapper 接口上添加 @CacheNamespace 注解

二級緩存是 Mapper 級別的,需在具體的 Mapper 接口上添加注解,標(biāo)識(shí)該 Mapper 開啟二級緩存。

package com.example.mpdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
import org.apache.ibatis.annotations.CacheNamespace;
import org.springframework.stereotype.Repository;
// 開啟二級緩存,eviction=緩存回收策略,flushInterval=緩存刷新間隔(毫秒)
@CacheNamespace(eviction = org.apache.ibatis.cache.decorators.LruCache.class, flushInterval = 60000)
@Repository
public interface UserMapper extends BaseMapper<User> {
    // 接口方法不變
}

5.1.2 二級緩存注意事項(xiàng)

  • 緩存的數(shù)據(jù)必須是可序列化的(實(shí)體類需實(shí)現(xiàn) Serializable 接口),否則會(huì)報(bào)錯(cuò);
  • 二級緩存適用于查詢頻繁、修改較少的數(shù)據(jù)(如字典表、配置表),避免緩存雪崩;
  • 當(dāng) Mapper 中的增刪改方法被調(diào)用時(shí),該 Mapper 的二級緩存會(huì)自動(dòng)清空,保證數(shù)據(jù)一致性;
  • 對于關(guān)聯(lián)查詢的緩存,需在關(guān)聯(lián)的 Mapper 接口上也開啟二級緩存,避免緩存失效。

5.2 批量操作:saveBatch、updateBatchById 的注意事項(xiàng)

MyBatis-Plus 提供了批量新增(saveBatch)、批量更新(updateBatchById)等批量操作方法,相比循環(huán)調(diào)用單條操作,批量操作能減少數(shù)據(jù)庫連接次數(shù),提升操作效率。但在使用時(shí)需注意以下細(xì)節(jié),避免出現(xiàn)性能問題或數(shù)據(jù)異常。

5.2.1 批量操作核心注意事項(xiàng)

  • 批次大小控制:saveBatch、updateBatchById 方法默認(rèn)批次大小為 1000(即每 1000 條數(shù)據(jù)執(zhí)行一次批量 SQL)。若批量操作的數(shù)據(jù)量過大(如 10 萬條),無需修改默認(rèn)批次大小(過大的批次會(huì)導(dǎo)致 SQL 語句過長,占用數(shù)據(jù)庫連接資源);若數(shù)據(jù)量較?。ㄈ鐜装贄l),可手動(dòng)指定批次大?。ㄈ?batchSize = 500)。
  • // 手動(dòng)指定批次大小為500 userService.saveBatch(userList, 500); userService.updateBatchById(userList, 500);
  • 數(shù)據(jù)庫連接配置優(yōu)化:批量操作需要占用數(shù)據(jù)庫連接較長時(shí)間,需在 application.yml 中優(yōu)化數(shù)據(jù)庫連接池配置(以 HikariCP 為例,Spring Boot 默認(rèn)連接池):
  • spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false username: root password: 123456 hikari: maximum-pool-size: 20 # 最大連接數(shù),根據(jù)服務(wù)器性能調(diào)整 minimum-idle: 5 # 最小空閑連接 connection-timeout: 30000 # 連接超時(shí)時(shí)間(毫秒) idle-timeout: 600000 # 空閑連接超時(shí)時(shí)間(毫秒)
  • 避免嵌套批量操作:不要在批量操作中嵌套另一個(gè)批量操作(如批量新增用戶時(shí),嵌套批量新增訂單),會(huì)導(dǎo)致數(shù)據(jù)庫連接耗盡,建議分步驟執(zhí)行,或使用事務(wù)控制。
  • 事務(wù)控制:批量操作建議添加事務(wù)注解(@Transactional),確保批量操作要么全部成功,要么全部失敗,避免數(shù)據(jù)不一致。
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
@Transactional(rollbackFor = Exception.class)
public boolean batchSaveUser(List userList) {
// 批量新增,添加事務(wù)控制
return saveBatch(userList, 500);
}
}

5.3 SQL 日志分析與慢查詢排查建議

在實(shí)際開發(fā)中,SQL 性能是影響系統(tǒng)響應(yīng)速度的關(guān)鍵因素。MyBatis-Plus 支持打印執(zhí)行的 SQL 日志,通過分析日志可以排查慢查詢、冗余查詢等問題,優(yōu)化 SQL 性能。

5.3.1 SQL 日志配置(application.yml)

已在環(huán)境搭建部分配置了日志打印(log-impl: org.apache.ibatis.logging.stdout.StdOutImpl),會(huì)在控制臺(tái)打印執(zhí)行的 SQL 語句、參數(shù)、執(zhí)行時(shí)間等信息,示例如下:

==>  Preparing: SELECT id,username,age FROM user WHERE (age > ?) LIMIT ?,?
==> Parameters: 20(Integer), 0(Long), 2(Long)
<==      Total: 2

5.3.2 慢查詢排查與優(yōu)化建議

  • 識(shí)別慢查詢:通過 SQL 日志中的執(zhí)行時(shí)間,判斷是否為慢查詢(一般認(rèn)為執(zhí)行時(shí)間超過 500ms 的 SQL 為慢查詢)。例如:若某條查詢 SQL 執(zhí)行時(shí)間達(dá)到 2000ms,需重點(diǎn)優(yōu)化。
  • 慢查詢優(yōu)化方法
    • 添加索引:對查詢條件中頻繁使用的字段(如 where、join on 后的字段)添加索引,減少數(shù)據(jù)庫掃描行數(shù);
    • 避免全表掃描:避免使用 select * 查詢所有字段,只查詢需要的字段;避免使用 or、not in 等關(guān)鍵字(可替換為 in、exists);
    • 優(yōu)化關(guān)聯(lián)查詢:減少關(guān)聯(lián)表的數(shù)量,對關(guān)聯(lián)字段添加索引;避免在關(guān)聯(lián)查詢中使用子查詢,可替換為 join;
    • 分頁查詢優(yōu)化:確保分頁查詢的排序字段有索引,避免分頁時(shí)出現(xiàn)全表排序;
    • 批量操作優(yōu)化:如前所述,使用 MyBatis-Plus 的批量方法,減少數(shù)據(jù)庫連接次數(shù)。
  • 日志進(jìn)階配置:對于生產(chǎn)環(huán)境,不建議將日志打印到控制臺(tái)(影響性能),可配置將 SQL 日志輸出到文件,并只打印慢查詢?nèi)罩荆ㄍㄟ^ Logback/Log4j2 配置),示例(Logback):

到此這篇關(guān)于MyBatis-Plus從基礎(chǔ)CRUD到高級查詢與性能優(yōu)化實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)mybatisplus crud查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springMVC中基于token防止表單重復(fù)提交方法

    springMVC中基于token防止表單重復(fù)提交方法

    本篇文章主要介紹了springMVC中基于token防止表單重復(fù)提交方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • Springboot Mybatis type-aliases-package錯(cuò)誤的解決方案

    Springboot Mybatis type-aliases-package錯(cuò)誤的解決方案

    在使用Spring Boot 2.7.0整合MyBatis 2.1.3時(shí),遇到mybatis.type-aliases-package配置后XML別名爆紅的問題,通過在model類上添加@Alias注解,為類定義別名,解決了問題
    2026-02-02
  • Java使用hutool實(shí)現(xiàn)文件大小的友好輸出

    Java使用hutool實(shí)現(xiàn)文件大小的友好輸出

    這篇文章主要為大家詳細(xì)介紹了Java如何使用hutool實(shí)現(xiàn)文件大小的友好輸出,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下
    2023-11-11
  • Java實(shí)現(xiàn)郵件找回密碼功能

    Java實(shí)現(xiàn)郵件找回密碼功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)郵件找回密碼功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • 簡單了解Spring Cloud Alibaba相關(guān)知識(shí)

    簡單了解Spring Cloud Alibaba相關(guān)知識(shí)

    這篇文章主要介紹了簡單了解Spring Cloud Alibaba相關(guān)知識(shí),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決

    InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決

    這篇文章主要介紹了InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java開發(fā)中synchronized的定義及用法詳解

    Java開發(fā)中synchronized的定義及用法詳解

    這篇文章主要介紹了Java開發(fā)中synchronized的定義及用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java多線程實(shí)現(xiàn)之Callable詳解

    Java多線程實(shí)現(xiàn)之Callable詳解

    這篇文章主要介紹了Java多線程實(shí)現(xiàn)之Callable詳解,Callable是一個(gè)接口,用于實(shí)現(xiàn)多線程,與實(shí)現(xiàn)Runnable類似,但是功能更強(qiáng)大,通過實(shí)現(xiàn)Callable接口,我們需要重寫call()方法,該方法可以在任務(wù)結(jié)束后提供一個(gè)返回值,需要的朋友可以參考下
    2023-08-08
  • java實(shí)現(xiàn)簡單登錄界面的實(shí)戰(zhàn)過程

    java實(shí)現(xiàn)簡單登錄界面的實(shí)戰(zhàn)過程

    學(xué)習(xí)JAVA的過程當(dāng)中,登陸界面是多數(shù)人第一個(gè)實(shí)現(xiàn)的小程序,下面這篇文章主要給大家介紹了關(guān)于利用java實(shí)現(xiàn)簡單登錄界面的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • java 多態(tài)性詳解及簡單實(shí)例

    java 多態(tài)性詳解及簡單實(shí)例

    這篇文章主要介紹了java 多態(tài)性詳解及簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02

最新評論

蓝田县| 洛宁县| 邢台县| 普兰县| 香格里拉县| 上高县| 左云县| 远安县| 台北县| 诸暨市| 祁连县| 宜丰县| 津市市| 碌曲县| 依兰县| 桃源县| 蒙阴县| 罗源县| 星子县| 南溪县| 黔东| 正镶白旗| 沂源县| 光山县| 湖州市| 天门市| 永定县| 泰兴市| 阿拉善右旗| 山阳县| 巫溪县| 蒙城县| 宣武区| 子洲县| 平远县| 商都县| 清水县| 宁陵县| 洱源县| 象山县| 东方市|