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

MyBatisPlus 15個(gè)高級(jí)用法詳解

 更新時(shí)間:2026年03月07日 14:42:14   作者:程序員大華  
MyBatis-Plus(簡(jiǎn)稱MP)是Java后端開發(fā)中非常流行的ORM框架,它能夠簡(jiǎn)化CRUD操作,下面給大家分享MyBatisPlus 15個(gè)高級(jí)用法,感興趣的朋友跟隨小編一起看看吧

大家好,我是大華!相信Java后端開發(fā)的朋友們對(duì)MyBatis-Plus(簡(jiǎn)稱MP)肯定不陌生,它可以讓CRUD的操作瞬間起飛。

今天就給大家分享15個(gè)使用技巧。

1. Service 和 Mapper?

IService:內(nèi)置了海量現(xiàn)成方法,save, update, list, page 等,適用于絕大多數(shù)單表 CRUD。 BaseMapper:當(dāng)需要進(jìn)行復(fù)雜聯(lián)表查詢、或者要寫自定義 SQL 時(shí),它就是你的主戰(zhàn)場(chǎng)。

// 簡(jiǎn)單查詢,用 Service 的 lambdaQuery
List<User> users = userService.lambdaQuery()
                .eq(User::getStatus, 1)
                .like(User::getName, "張")
                .list();
// 復(fù)雜查詢,用 Mapper + XML 或注解!
// 在 UserMapper.java 中
@Select("SELECT u.*, d.dept_name FROM user u LEFT JOIN dept d ON u.dept_id = d.id WHERE u.id = #{userId}")
UserVO selectUserDetail(@Param("userId") Long userId);

別在 Service 里硬塞復(fù)雜 SQL,該寫 XML 的時(shí)候還是不能偷懶。

2. Lambda 表達(dá)式

MP 最棒的特性之一就是 Lambda 查詢,編譯期就能發(fā)現(xiàn)字段名錯(cuò)誤,告別運(yùn)行時(shí)才發(fā)現(xiàn)拼錯(cuò)的尷尬。

// 【錯(cuò)誤姿勢(shì)】字段名是字符串,容易拼錯(cuò),編譯器不報(bào)錯(cuò)
userService.lambdaQuery().eq("naem", "張三"); // 運(yùn)行才報(bào)錯(cuò),哭死!
// 【正確姿勢(shì)】使用方法引用,安全又優(yōu)雅
userService.lambdaQuery().eq(User::getName, "張三"); 
// 編譯不通過,立馬改正!

3. 分頁(yè)查詢,不只是PageHelper的替代品

MP 的分頁(yè)功能非常強(qiáng)大,而且與自身?xiàng)l件構(gòu)造器無縫集成。

// 創(chuàng)建分頁(yè)參數(shù),并指定排序
Page<User> page = new Page<>(1, 20); // 查第1頁(yè),每頁(yè)20條
page.addOrder(OrderItem.desc("create_time")); // 按創(chuàng)建時(shí)間倒序
// 執(zhí)行分頁(yè)查詢
Page<User> userPage = userService.page(page,
        Wrappers.<User>lambdaQuery()
                .eq(User::getDeptId, 2)
);
// 直接轉(zhuǎn)換為 VO 分頁(yè)對(duì)象,一步到位
Page<UserVO> voPage = userPage.convert(user -> {
    UserVO vo = new UserVO();
    BeanUtils.copyProperties(user, vo); // 使用 Spring 的工具類
    // 或者用 MapStruct 等更專業(yè)的工具
    return vo;
});

4. 批量操作,性能提升的關(guān)鍵

大批量數(shù)據(jù)插入/更新時(shí),一條條處理會(huì)讓數(shù)據(jù)庫(kù)哭泣。

// 批量插入,分批提交
List<User> hugeUserList = ... // 一個(gè)巨大的列表
userService.saveBatch(hugeUserList, 1000); // 每1000條批量提交一次
// 批量更新(自己控制事務(wù))
@Transactional(rollbackFor = Exception.class)
public void batchUpdateStatus(List<Long> ids, Integer status) {
    List<User> updateList = ids.stream().map(id -> {
        User user = new User();
        user.setId(id);
        user.setStatus(status);
        return user;
    }).collect(Collectors.toList());
    userService.updateBatchById(updateList);
}

5. 條件構(gòu)造器,讓你的邏輯更清晰

QueryWrapperLambdaQueryWrapper可以構(gòu)建非常復(fù)雜的查詢邏輯。

// 復(fù)雜的 AND-OR 組合查詢
List<User> users = userService.lambdaQuery()
    .eq(User::getStatus, 1)
    .and(wrapper -> wrapper // 這是一個(gè) AND 嵌套
        .like(User::getName, "張")
        .or()
        .like(User::getEmail, "zhang") // name LIKE '%張%' OR email LIKE '%zhang%'
    )
    .between(User::getCreateTime, startTime, endTime)
    .list();
// 【性能技巧】只查需要的字段,避免 SELECT *
List<User> userList = userService.lambdaQuery()
    .select(User::getId, User::getName) // 只查詢 ID 和 Name 字段
    .eq(User::getStatus, 1)
    .list();

6. 自動(dòng)填充,告別手動(dòng) set 創(chuàng)建時(shí)間

create_time, update_time 這種字段,就別再手動(dòng) set 了。

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // 插入時(shí)自動(dòng)填充
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUser());
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新時(shí)自動(dòng)填充
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}
// 實(shí)體類字段上需要加注解
public class User {
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

7. 邏輯刪除,數(shù)據(jù)不是真的刪除

千萬(wàn)別用 delete from 硬刪數(shù)據(jù)了!

# 在 application.yml 中配置
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted  # 全局邏輯刪除實(shí)體字段名
      logic-delete-value: 1        # 邏輯已刪除值(默認(rèn)為 1)
      logic-not-delete-value: 0    # 邏輯未刪除值(默認(rèn)為 0)

配置后,調(diào)用 userService.removeById(1),MP 實(shí)際執(zhí)行的是: UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0。 所有查詢也會(huì)自動(dòng)帶上 AND deleted = 0 條件。

8. 枚舉處理器,告別數(shù)據(jù)庫(kù)存數(shù)字的迷惑行為

數(shù)據(jù)庫(kù)存 status = 1,代碼里還要猜 1 是啥意思?用枚舉!

@Getter
public enum UserStatus {
    ENABLED(1, "啟用"),
    DISABLED(0, "禁用");
    private final int code;
    private final String desc;
    UserStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }
}
// 實(shí)體類中直接使用枚舉類型
public class User {
    private UserStatus status;
}
// 配置枚舉處理器(Spring Boot 基本不用配了,開箱即用)

這樣,數(shù)據(jù)庫(kù)存的是數(shù)字 1,但代碼里操作的一直是 UserStatus.ENABLED,清晰明了!

9. 多租戶數(shù)據(jù)隔離,SAAS 系統(tǒng)必備

SAAS 應(yīng)用中,不同租戶的數(shù)據(jù)必須嚴(yán)格隔離。MP 的租戶插件可以自動(dòng)在每次查詢時(shí)加上租戶 ID。

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 租戶插件
        TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor();
        tenantInterceptor.setTenantLineHandler(new TenantLineHandler() {
            @Override
            public Expression getTenantId() {
                // 從當(dāng)前上下文中獲取租戶ID,比如從 JWT Token 中
                return new StringValue(TenantContext.getCurrentTenantId());
            }
            @Override
            public String getTenantIdColumn() {
                return "tenant_id"; // 數(shù)據(jù)庫(kù)中的租戶ID列名
            }
            @Override
            public boolean ignoreTable(String tableName) {
                // 忽略不需要租戶隔離的表,如全局配置表
                return "system_config".equals(tableName);
            }
        });
        interceptor.addInnerInterceptor(tenantInterceptor);
        return interceptor;
    }
}

10. 代碼生成器,效率翻倍利器

別再手?jǐn)] Entity, Mapper, Service, Controller 了!

public class CodeGenerator {
    public static void main(String[] args) {
        AutoGenerator generator = new AutoGenerator();
        // 數(shù)據(jù)源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/test");
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("123456");
        generator.setDataSource(dataSourceConfig);
        // 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
        globalConfig.setAuthor("大華");
        globalConfig.setOpen(false);
        globalConfig.setSwagger2(true); // 實(shí)體屬性 Swagger2 注解
        generator.setGlobalConfig(globalConfig);
        // 包配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("com.laomao.demo");
        packageConfig.setEntity("domain.entity");
        packageConfig.setMapper("dao.mapper");
        packageConfig.setService("service");
        packageConfig.setServiceImpl("service.impl");
        generator.setPackageInfo(packageConfig);
        generator.execute(); // 執(zhí)行生成
    }
}

運(yùn)行一下,全套代碼瞬間生成!

11. 自定義全局?jǐn)r截器,統(tǒng)一處理邏輯

可以用來做數(shù)據(jù)權(quán)限控制、SQL 性能監(jiān)控、字段加解密等。

@Component
@Slf4j
public class SqlLogInterceptor implements InnerInterceptor {
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, BoundSql boundSql) {
        long start = System.currentTimeMillis();
        // 將開始時(shí)間存入當(dāng)前線程上下文
    }
    @Override
    public void afterQuery(Executor executor, MappedStatement ms, Object parameter, BoundSql boundSql, List<Object> result) {
        long end = System.currentTimeMillis();
        long cost = end - start;
        if (cost > 1000) { // 超過1秒算慢SQL
            log.warn("慢SQL警告: {}, 執(zhí)行耗時(shí): {}ms", boundSql.getSql(), cost);
            // 可以接入告警系統(tǒng),通知開發(fā)人員
        }
    }
}

12. 分布式主鍵 ID,告別數(shù)據(jù)庫(kù)自增

在分布式系統(tǒng)中,數(shù)據(jù)庫(kù)自增 ID 是瓶頸。推薦使用雪花算法。

public class User {
    // 指定主鍵類型為 ASSIGN_ID(雪花算法)
    @TableId(type = IdType.ASSIGN_ID)
    private Long id; // 注意是 Long,不是 Integer
    // ...
}

13. 樂觀鎖,防止并發(fā)更新覆蓋

高并發(fā)下,防止后提交的數(shù)據(jù)覆蓋先提交的數(shù)據(jù)。

// 實(shí)體類中增加版本號(hào)字段
public class User {
    @Version
    private Integer version;
}
// 更新時(shí),MP會(huì)自動(dòng)帶上版本號(hào)條件
User user = userService.getById(1L);
user.setName("新名字");
userService.updateById(user); // SQL: UPDATE user SET name=?, version=? WHERE id=? AND version=?

14. 結(jié)果映射,自動(dòng)處理一對(duì)一、一對(duì)多

MP 可以和 MyBatis 的 @Result 注解完美結(jié)合。

// 在 Mapper 方法上使用復(fù)雜結(jié)果映射
@Select("SELECT u.*, d.name as dept_name FROM user u LEFT JOIN department d ON u.dept_id = d.id WHERE u.id = #{id}")
@Results({
    @Result(column = "id", property = "id"),
    @Result(column = "dept_name", property = "deptName"),
    @Result(column = "id", property = "roles", 
            many = @Many(select = "com.laomao.mapper.RoleMapper.findByUserId"))
})
UserVO findUserWithDept(Long id);

15. 事務(wù)管理,保證數(shù)據(jù)一致性

這是最后一道防線,也是最關(guān)鍵的一道。

@Service
public class UserService {
    @Transactional(rollbackFor = Exception.class) // 注意:默認(rèn)只回滾 RuntimeException
    public void createUserWithInitData(User user) {
        // 1. 保存用戶基本信息
        userService.save(user);
        // 2. 初始化用戶賬戶
        Account account = new Account();
        account.setUserId(user.getId());
        accountService.save(account);
        // 3. 發(fā)送歡迎消息(如果消息發(fā)送失敗,希望用戶創(chuàng)建也回滾)
        messageService.sendWelcomeMessage(user.getId());
        // 任何一個(gè)步驟出錯(cuò),所有操作都會(huì)回滾
    }
}

總結(jié)

MyBatis-Plus 的強(qiáng)大遠(yuǎn)不止于此,但掌握以上 15個(gè)核心技巧,足以讓你在日常開發(fā)中游刃有余,寫出既高效又優(yōu)雅的代碼。

到此這篇關(guān)于MyBatisPlus 高級(jí)用法詳解的文章就介紹到這了,更多相關(guān)MyBatisPlus用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java如何限制IP訪問頁(yè)面

    Java如何限制IP訪問頁(yè)面

    這篇文章主要介紹了Java如何限制IP訪問頁(yè)面,幫助大家完成需求,實(shí)現(xiàn)白名單,感興趣的朋友可以了解下
    2020-09-09
  • Java總結(jié)篇系列:Java泛型詳解

    Java總結(jié)篇系列:Java泛型詳解

    下面小編就為大家?guī)硪黄狫ava總結(jié)篇系列:Java泛型詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-09-09
  • 詳解Java的MyBatis框架中的緩存與緩存的使用改進(jìn)

    詳解Java的MyBatis框架中的緩存與緩存的使用改進(jìn)

    很多人在使用MyBatis的緩存后經(jīng)常會(huì)遇到MySQL分頁(yè)查詢的顯示問題,針對(duì)于此,這里我們就來詳解Java的MyBatis框架中的緩存與緩存的使用改進(jìn),首先來回顧一下MyBatis的緩存機(jī)制與執(zhí)行:
    2016-06-06
  • 老生常談Java?網(wǎng)絡(luò)編程?——?Socket?詳解

    老生常談Java?網(wǎng)絡(luò)編程?——?Socket?詳解

    這篇文章主要介紹了Java?網(wǎng)絡(luò)編程?——?Socket?相關(guān)知識(shí),本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • java按字節(jié)截取帶有漢字的字符串的解法(推薦)

    java按字節(jié)截取帶有漢字的字符串的解法(推薦)

    下面小編就為大家?guī)硪黄猨ava按字節(jié)截取帶有漢字的字符串的解法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-09-09
  • java Nio使用NioSocket客戶端與服務(wù)端交互實(shí)現(xiàn)方式

    java Nio使用NioSocket客戶端與服務(wù)端交互實(shí)現(xiàn)方式

    這篇文章主要介紹了java Nio使用 NioSocket 客戶端與服務(wù)端交互實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java中json處理工具JsonPath的使用教程

    Java中json處理工具JsonPath的使用教程

    JsonPath類似于XPath,是一種json數(shù)據(jù)結(jié)構(gòu)節(jié)點(diǎn)定位和導(dǎo)航表達(dá)式語(yǔ)言,這篇文章主要為大家介紹了JsonPath的基本使用,需要的小伙伴可以參考下
    2023-08-08
  • C++ 歸并排序(merge sort)案例詳解

    C++ 歸并排序(merge sort)案例詳解

    這篇文章主要介紹了C++ 歸并排序(merge sort)案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java Map集合使用方法全面梳理

    Java Map集合使用方法全面梳理

    Map是一種依照鍵(key)存儲(chǔ)元素的容器,鍵(key)很像下標(biāo),在List中下標(biāo)是整數(shù)。在Map中鍵(key)可以使任意類型的對(duì)象。Map中不能有重復(fù)的鍵(Key),每個(gè)鍵(key)都有一個(gè)對(duì)應(yīng)的值(value)。一個(gè)鍵(key)和它對(duì)應(yīng)的值構(gòu)成map集合中的一個(gè)元素
    2022-04-04
  • Java三種求水仙花數(shù)的方法

    Java三種求水仙花數(shù)的方法

    本篇文章通過求水仙花數(shù)的實(shí)例來讓大家對(duì)JAVA求數(shù)的概念和方法有更深入的理解和應(yīng)用,學(xué)習(xí)參考下吧。
    2018-02-02

最新評(píng)論

麟游县| 循化| 仲巴县| 碌曲县| 霍邱县| 托里县| 乐平市| 璧山县| 乌拉特中旗| 富阳市| 永宁县| 姚安县| 岢岚县| 修武县| 杭锦后旗| 潮安县| 淄博市| 慈溪市| 长泰县| 马关县| 鹤山市| 密云县| 依兰县| 浮梁县| 霸州市| 孟村| 江津市| 文昌市| 板桥市| 黔东| 大英县| 苏州市| 寻乌县| 青州市| 横山县| 永城市| 东海县| 叙永县| 顺平县| 靖安县| 密云县|