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

Mybatis-Plus超級實用的多種功能用法詳解

 更新時間:2026年01月28日 17:12:51   作者:loading小馬  
Mybatis-Plus是一款基于MyBatis的增強型ORM框架,旨在簡化CRUD操作并提高開發(fā)效率,這篇文章給大家介紹Mybatis-Plus超級實用的多種功能用法,感興趣的朋友一起看看吧

一、Mybatis-Plus介紹

1.1、什么是 MyBatis-Plus

        MyBatis-Plus 是一款基于 MyBatis 的增強型 ORM 框架,由國內(nèi)團(tuán)隊(苞米豆)開發(fā)維護(hù),遵循「只做增強,不做改變」的核心設(shè)計理念 —— 它完全兼容 MyBatis 的原有功能,同時在其基礎(chǔ)上封裝了大量常用操作,極大簡化了 MyBatis 的開發(fā)流程,減少了重復(fù)的 CRUD 代碼編寫工作。 

        簡單來說:MyBatis 是「半自動化」ORM 框架(需要手動寫 SQL),而 MyBatis-Plus 在此基礎(chǔ)上,通過內(nèi)置的通用 Mapper/Service,讓開發(fā)者無需編寫基礎(chǔ) SQL 就能完成大部分?jǐn)?shù)據(jù)庫操作,同時保留了 MyBatis 靈活定制 SQL 的能力。

1.2、核心定位

  • 增強:對 MyBatis 無侵入式增強,原有 MyBatis 代碼無需修改即可集成。
  • 高效:大幅減少 CRUD 代碼、XML 配置的編寫量。
  • 靈活:支持自定義 SQL、多數(shù)據(jù)源、插件擴展等高級特性。

1.3、優(yōu)勢

  1. 無侵入性:完全基于 MyBatis 擴展,不修改 MyBatis 核心源碼,兼容所有 MyBatis 原生功能。
  2. 強大的 CRUD 封裝:內(nèi)置通用 Mapper/Service,單表操作無需編寫任何 SQL 即可完成增刪改查。
  3. 支持 Lambda 表達(dá)式:通過 Lambda 語法構(gòu)建查詢條件,避免硬編碼字段名,減少拼寫錯誤。
  4. 自動分頁:內(nèi)置分頁插件,無需手動處理分頁邏輯,支持多種數(shù)據(jù)庫(MySQL、Oracle、PostgreSQL 等)。
  5. 主鍵生成策略:內(nèi)置多種主鍵生成策略(雪花算法、自增、UUID 等),可靈活配置。
  6. 邏輯刪除:無需手動寫刪除邏輯,通過標(biāo)記字段(如 deleted)實現(xiàn)邏輯刪除,保留數(shù)據(jù)。
  7. 樂觀鎖:內(nèi)置樂觀鎖插件,輕松解決并發(fā)更新問題。
  8. 代碼生成器:支持快速生成 Entity、Mapper、Service、Controller 等全套代碼,提升開發(fā)效率。

二、Mybatis-Plus快速入門

2.1、引入依賴配置

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

2.2、xml配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis-Plus 配置
mybatis-plus:
  # 實體類別名包路徑
  type-aliases-package: com.example.mpdemo.entity
  # XML映射文件路徑
  mapper-locations: classpath:mapper/**/*.xml
  # 配置日志(方便調(diào)試SQL)
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 全局配置
  global-config:
    db-config:
      # 主鍵生成策略:雪花算法(適用于分布式)
      id-type: ASSIGN_ID
      # 邏輯刪除字段名
      logic-delete-field: deleted
      # 邏輯刪除-未刪除值
      logic-not-delete-value: 0
      # 邏輯刪除-已刪除值
      logic-delete-value: 1

2.3、實體類

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data // Lombok注解,簡化get/set
@TableName("user") // 指定數(shù)據(jù)庫表名(默認(rèn)類名駝峰轉(zhuǎn)下劃線)
public class User {
    // 主鍵,使用雪花算法生成
    @TableId(type = IdType.AUTO)
    private Long id;
    // 普通字段(默認(rèn)字段名駝峰轉(zhuǎn)下劃線,如userName -> user_name)
    private String userName;
    private Integer age;
    private String email;
    // 邏輯刪除字段(對應(yīng)全局配置的deleted)
    @TableLogic
    private Integer deleted;
    // 自動填充創(chuàng)建時間
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    // 自動填充更新時間
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

2.4、Mapper接口

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
import org.apache.ibatis.annotations.Mapper;
// 繼承BaseMapper即可獲得所有CRUD方法,無需編寫任何SQL
@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 如需自定義SQL,可在此添加方法并在XML中實現(xiàn)
}

2.5、測試

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 MpDemoTest {
    @Autowired
    private UserService userService;
    // 新增
    @Test
    public void testAdd() {
        User user = new User();
        user.setUserName("張三");
        user.setAge(20);
        user.setEmail("zhangsan@example.com");
        userService.save(user);
    }
    // 查詢所有
    @Test
    public void testList() {
        List<User> userList = userService.list();
        userList.forEach(System.out::println);
    }
    // 條件查詢 + 分頁
    @Test
    public void testPage() {
        // 構(gòu)建分頁條件:第1頁,每頁10條
        Page<User> page = new Page<>(1, 10);
        // 構(gòu)建查詢條件:年齡大于18
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .gt(User::getAge, 18);
        // 分頁查詢
        Page<User> userPage = userService.page(page, wrapper);
        // 輸出結(jié)果
        System.out.println("總條數(shù):" + userPage.getTotal());
        System.out.println("總頁數(shù):" + userPage.getPages());
        userPage.getRecords().forEach(System.out::println);
    }
}

三、Mybatis-Plus的功能使用

3.1、BaseMapper<User>

在mybatis中如果不想寫xml中的表的curd代碼,就可以使用mybatisplus中提供的繼承BaseMapper<User>,然后在mapper接口層中去繼承。

注意:要指定實體類泛型,只有指定了泛型,mybatisplus才知道操作哪個實體的curd,下面我以user實體為例

package com.itheima.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper extends BaseMapper<User> {
    void saveUser(User user);
    void deleteUser(Long id);
    void updateUser(User user);
    User queryUserById(@Param("id") Long id);
    List<User> queryUserByIds(@Param("ids") List<Long> ids);
}

3.2、常見注解

在mybatisplus中有一些約定如下:

  1. 在實體類里面,類名駝峰轉(zhuǎn)下劃線作為表名
  2. 名為id的字段作為主鍵
  3. 變量名駝峰轉(zhuǎn)下劃線作為表的字段名

        如果實體和表的關(guān)系不符合上述mp的約定,那么就需要自己去定義表名和字段名,那么如何去定義呢?答案是

@TableName:用來指定表名,

@TableId用來指定表中的主鍵字段信息,如果不添加type的值,默認(rèn)type=ASSIGN_ID,生成long類型的id

@TableFiled用來指定表中普通字段信息

注意:

  • 以屬性名is開頭且是bool類型,就算符合約定也需要加上@TableField主鍵
  • 成員變量名與數(shù)據(jù)庫關(guān)鍵字沖突時,要加上@TableField注解,且里面的值要用反引號引起來
  • 成員變量不是字段值,需要加上@TableField,且指定exist=false。

3.3、常見配置

        注意:配置中id-type如果是assign_id,而類注解上@TableId("",type=IdType.Auto),那么由于注解優(yōu)先級高于全局配置優(yōu)先級,所以type=IdType.Auto會生效,但是如果沒有指定的話,那么全局配置將生效

3.4、條件構(gòu)造器

        除了新增以外,修改、刪除、查詢的SQL語句都需要指定where條件。因此mybatis-plus中BaseMapper提供的相關(guān)方法除了以id作為where條件以外,還支持更加復(fù)雜的where條件。

參數(shù)中的Wrapper就是條件構(gòu)造的抽象類,其下有很多默認(rèn)實現(xiàn),繼承關(guān)系如圖:

接下來,我們就來看看如何利用Wrapper實現(xiàn)復(fù)雜查詢。

3.4.1、QueryWrapper

無論是修改、刪除、查詢,都可以使用QueryWrapper來構(gòu)建查詢條件。

接下來看一些例子:

查詢:查詢出名字中帶o的,存款大于等于1000元的人。代碼如下:

@Test
void testQueryWrapper() {
    // 1.構(gòu)建查詢條件 where name like "%o%" AND balance >= 1000
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            .select("id", "username", "info", "balance")
            .like("username", "o")
            .ge("balance", 1000);
    // 2.查詢數(shù)據(jù)
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

更新:更新用戶名為jack的用戶的余額為2000,代碼如下:

@Test
void testUpdateByQueryWrapper() {
    // 1.構(gòu)建查詢條件 where name = "Jack"
    QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "Jack");
    // 2.更新數(shù)據(jù),user中非null字段都會作為set語句
    User user = new User();
    user.setBalance(2000);
    userMapper.update(user, wrapper);
}

3.4.2、UpdateWrapper

基于BaseMapper中的update方法更新時只能直接賦值,對于一些復(fù)雜的需求就難以實現(xiàn)。 例如:更新id為1,2,4的用戶的余額,扣200,對應(yīng)的SQL應(yīng)該是:

UPDATE user SET balance = balance - 200 WHERE id in (1, 2, 4)

SET的賦值結(jié)果是基于字段現(xiàn)有值的,這個時候就要利用UpdateWrapper中的setSql功能了:

@Test
void testUpdateWrapper() {
    List<Long> ids = List.of(1L, 2L, 4L);
    // 1.生成SQL
    UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
            .setSql("balance = balance - 200") // SET balance = balance - 200
            .in("id", ids); // WHERE id in (1, 2, 4)
        // 2.更新,注意第一個參數(shù)可以給null,也就是不填更新字段和數(shù)據(jù),
    // 而是基于UpdateWrapper中的setSQL來更新
    userMapper.update(null, wrapper);
}

3.4.3、LambdaQueryWrapper

     無論是QueryWrapper還是UpdateWrapper在構(gòu)造條件的時候都需要寫死字段名稱,會出現(xiàn)字符串魔法值。這在編程規(guī)范中顯然是不推薦的。 那怎么樣才能不寫字段名,又能知道字段名呢?

其中一種辦法是基于變量的gettter方法結(jié)合反射技術(shù)。因此我們只要將條件對應(yīng)的字段的getter方法傳遞給MybatisPlus,它就能計算出對應(yīng)的變量名了。而傳遞方法可以使用JDK8中的方法引用Lambda表達(dá)式。 因此MybatisPlus又提供了一套基于Lambda的Wrapper,包含兩個:

  • LambdaQueryWrapper
  • LambdaUpdateWrapper

分別對應(yīng)QueryWrapper和UpdateWrapper

其使用方式如下:

@Test
void testLambdaQueryWrapper() {
    // 1.構(gòu)建條件 WHERE username LIKE "%o%" AND balance >= 1000
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.lambda()
            .select(User::getId, User::getUsername, User::getInfo, User::getBalance)
            .like(User::getUsername, "o")
            .ge(User::getBalance, 1000);
    // 2.查詢
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

3.5、自定義SQL

先來看一個案例代碼:

      這種寫法在一些企業(yè)也是不允許的,因為SQL語句最好都維護(hù)在持久層,而不是業(yè)務(wù)層。就當(dāng)前案例來說,由于條件是in語句,只能將SQL寫在Mapper.xml文件,利用foreach來生成動態(tài)SQL。 這實在是太麻煩了。假如查詢條件更復(fù)雜,動態(tài)SQL的編寫也會更加復(fù)雜。

所以,MybatisPlus提供了自定義SQL功能,可以讓我們利用Wrapper生成查詢條件,再結(jié)合Mapper.xml編寫SQL

@Test
void testCustomWrapper() {
    // 1.準(zhǔn)備自定義查詢條件
    List<Long> ids = List.of(1L, 2L, 4L);
    QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);

    // 2.調(diào)用mapper的自定義方法,直接傳遞Wrapper
    userMapper.deductBalanceByIds(200, wrapper);
}

然后在UserMapper中自定義SQL:

package com.itheima.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Param;
public interface UserMapper extends BaseMapper<User> {
    @Select("UPDATE user SET balance = balance - #{money} ${ew.customSqlSegment}")
    void deductBalanceByIds(@Param("money") int money, @Param("ew") QueryWrapper<User> wrapper);
}

3.6、Iservice接口

3.6.1、基本用法

MybatisPlus不僅提供了BaseMapper,還提供了通用的Service接口及默認(rèn)實現(xiàn),封裝了一些常用的service模板方法。 通用接口為IService,默認(rèn)實現(xiàn)為ServiceImpl,其中封裝的方法可以分為以下幾類:

  • save:新增
  • remove:刪除
  • update:更新
  • get:查詢單個結(jié)果
  • list:查詢集合結(jié)果
  • count:計數(shù)
  • page:分頁查詢

        由于Service中經(jīng)常需要定義與業(yè)務(wù)有關(guān)的自定義方法,因此我們不能直接使用IService,而是自定義Service接口,然后繼承IService以拓展方法。同時,讓自定義的Service實現(xiàn)類繼承ServiceImpl,這樣就不用自己實現(xiàn)IService中的接口了。

package com.itheima.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;
public interface IUserService extends IService<User> {
    // 拓展自定義方法
}
package com.itheima.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.po.service.IUserService;
import com.itheima.mp.mapper.UserMapper;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
                                                                                                        implements IUserService {
}

測試代碼:

package com.itheima.mp.controller;
import cn.hutool.core.bean.BeanUtil;
import com.itheima.mp.domain.dto.UserFormDTO;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;
import com.itheima.mp.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api(tags = "用戶管理接口")
@RequiredArgsConstructor
@RestController
@RequestMapping("users")
public class UserController {
    private final IUserService userService;
    @PostMapping
    @ApiOperation("新增用戶")
    public void saveUser(@RequestBody UserFormDTO userFormDTO){
        // 1.轉(zhuǎn)換DTO為PO
        User user = BeanUtil.copyProperties(userFormDTO, User.class);
        // 2.新增
        userService.save(user);
    }
    @DeleteMapping("/{id}")
    @ApiOperation("刪除用戶")
    public void removeUserById(@PathVariable("id") Long userId){
        userService.removeById(userId);
    }
    @GetMapping("/{id}")
    @ApiOperation("根據(jù)id查詢用戶")
    public UserVO queryUserById(@PathVariable("id") Long userId){
        // 1.查詢用戶
        User user = userService.getById(userId);
        // 2.處理vo
        return BeanUtil.copyProperties(user, UserVO.class);
    }
    @GetMapping
    @ApiOperation("根據(jù)id集合查詢用戶")
    public List<UserVO> queryUserByIds(@RequestParam("ids") List<Long> ids){
        // 1.查詢用戶
        List<User> users = userService.listByIds(ids);
        // 2.處理vo
        return BeanUtil.copyToList(users, UserVO.class);
    }
}

不過,一些帶有業(yè)務(wù)邏輯的接口則需要在service中自定義實現(xiàn)了。例如下面的需求:

  • 根據(jù)id扣減用戶余額

這看起來是個簡單修改功能,只要修改用戶余額即可。但這個業(yè)務(wù)包含一些業(yè)務(wù)邏輯處理:

  • 判斷用戶狀態(tài)是否正常
  • 判斷用戶余額是否充足

這些業(yè)務(wù)邏輯都要在service層來做,另外更新余額需要自定義SQL,要在mapper中來實現(xiàn)。因此,我們除了要編寫controller以外,具體的業(yè)務(wù)還要在service和mapper中編寫。

首先在UserController中定義一個方法:

@PutMapping("{id}/deduction/{money}")
@ApiOperation("扣減用戶余額")
public void deductBalance(@PathVariable("id") Long id, @PathVariable("money")Integer money){
    userService.deductBalance(id, money);
}

然后是UserService接口:

package com.itheima.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;
public interface IUserService extends IService<User> {
    void deductBalance(Long id, Integer money);
}

最后是UserServiceImpl實現(xiàn)類:

package com.itheima.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.mapper.UserMapper;
import com.itheima.mp.service.IUserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Override
    public void deductBalance(Long id, Integer money) {
        // 1.查詢用戶
        User user = getById(id);
        // 2.判斷用戶狀態(tài)
        if (user == null || user.getStatus() == 2) {
            throw new RuntimeException("用戶狀態(tài)異常");
        }
        // 3.判斷用戶余額
        if (user.getBalance() < money) {
            throw new RuntimeException("用戶余額不足");
        }
        // 4.扣減余額
        baseMapper.deductMoneyById(id, money);
    }
}

最后是mapper:

@Update("UPDATE user SET balance = balance - #{money} WHERE id = #{id}")
void deductMoneyById(@Param("id") Long id, @Param("money") Integer money);

3.6.2、Lambda

IService中還提供了Lambda功能來簡化我們的復(fù)雜查詢及更新功能。

案例一:實現(xiàn)復(fù)雜條件查詢用戶接口(根據(jù)name,status,minBalance,maxBalance,可以為空)做條件查詢

//實現(xiàn)復(fù)雜條件查詢用戶接口(根據(jù)name,status,minBalance,maxBalance,可以為空)做條件查詢
@ApiOperation("lambdaQuery復(fù)雜條件查詢用戶接口")
@GetMapping("list")
private List<UserVO> listByIds(UserQuery userQuery){
    List<User> users = userService.getUserList(userQuery.getName(), userQuery.getStatus(), userQuery.getMinBalance(), userQuery.getMaxBalance());
    return BeanUtil.copyToList(users, UserVO.class);
}
@Override
public List<User> getUserList(String name, Integer status, Integer minBalance, Integer maxBalance) {
     return lambdaQuery()
            .like(name != null, User::getUsername, name)
            .eq(status != null, User::getStatus, status)
            .ge(minBalance != null, User::getBalance, minBalance)
            .le(maxBalance != null, User::getBalance, maxBalance)
            .list();
}

案例二:根據(jù)id實現(xiàn)扣減余額

//IService的lambdaUpdate方法實現(xiàn)id扣減余額
@ApiOperation("lambdaUpdate方法實現(xiàn)id扣減余額")
@PutMapping("/{id}/lambdaUpdate/{money}")
private void lambdaUpdateById(@ApiParam ("用戶id") @PathVariable Long id,@ApiParam("扣減余額") @PathVariable Long money){
    //sql:update user set balance = balance - #{money} where id = #{id};
    userService.lambdaUpdateById(id, money);
}
@Override
@Transactional
public void lambdaUpdateById(Long id, Long money) {
    //1、查詢用戶
    User user=getById(id);
    if(user==null||user.getStatus()==2){
        throw new RuntimeException("用戶狀態(tài)異常");
    }
    //2、判斷余額狀態(tài)
    if(user.getBalance()-money<0){
        throw new RuntimeException("余額不足");
    }
    long remainBalance=user.getBalance()-money;
    lambdaUpdate()
    .set(User::getBalance,remainBalance)
    .set(remainBalance==0,User::getStatus,2)
    .eq(User::getId,id)
    .eq(User::getBalance,user.getBalance())//樂觀鎖
    .update();
}

3.6.3、IService的批量新增

MybatisPlus的批處理是基于PrepareStatement的預(yù)編譯模式,然后批量提交,最終在數(shù)據(jù)庫執(zhí)行時還是會有多條insert語句,逐條插入數(shù)據(jù)。SQL類似這樣:

Preparing: INSERT INTO user ( username, password, phone, info, balance, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )
Parameters: user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01
Parameters: user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01
Parameters: user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01

而如果想要得到最佳性能,最好是將多條SQL合并為一條,像這樣:

INSERT INTO user ( username, password, phone, info, balance, create_time, update_time )
VALUES 
(user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01),
(user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01),
(user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01),
(user_4, 123, 18688190004, "", 2000, 2023-07-01, 2023-07-01);

該怎么做呢?

MySQL的客戶端連接參數(shù)中有這樣的一個參數(shù):rewriteBatchedStatements。顧名思義,就是重寫批處理的statement語句。參考文檔:

https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-connp-props-performance-extensions.html#cj-conn-prop_rewriteBatchedStatements

這個參數(shù)的默認(rèn)值是false,我們需要修改連接參數(shù),將其配置為true

修改項目中的application.yml文件,在jdbc的url后面添加參數(shù)&rewriteBatchedStatements=true:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: MySQL123

再次測試插入數(shù)據(jù),可以發(fā)現(xiàn)速度有非常明顯的提升

3.7、代碼生成

      在使用MybatisPlus以后,基礎(chǔ)的Mapper、Service、PO代碼相對固定,重復(fù)編寫也比較麻煩。因此MybatisPlus官方提供了代碼生成器根據(jù)數(shù)據(jù)庫表結(jié)構(gòu)生成POMapper、Service等相關(guān)代碼。只不過代碼生成器同樣要編碼使用,也很麻煩。

這里推薦大家使用一款MybatisPlus的插件,它可以基于圖形化界面完成MybatisPlus的代碼生成,非常簡單。

3.7.1、安裝插件

Idea的plugins市場中搜索并安裝MyBatisPlus插件:

3.7.2、使用

首先需要配置數(shù)據(jù)庫地址,在Idea頂部菜單中,找到other,選擇Config Database

在彈出的窗口中填寫數(shù)據(jù)庫連接的基本信息:

點擊OK保存。

然后再次點擊Idea頂部菜單中的other,然后選擇Code Generator:

在彈出的表單中填寫信息:

最終,代碼自動生成到指定的位置了。

3.8、靜態(tài)工具

      有的時候Service之間也會相互調(diào)用,為了避免出現(xiàn)循環(huán)依賴問題,MybatisPlus提供一個靜態(tài)工具類Db,其中一些靜態(tài)方法與IService中方法簽名基本一致,也可以幫助我們實現(xiàn)CRUD功能

實例:

@Test
void testDbGet() {
    User user = Db.getById(1L, User.class);
    System.out.println(user);
}
@Test
void testDbList() {
    // 利用Db實現(xiàn)復(fù)雜條件查詢
    List<User> list = Db.lambdaQuery(User.class)
            .like(User::getUsername, "o")
            .ge(User::getBalance, 1000)
            .list();
    list.forEach(System.out::println);
}
@Test
void testDbUpdate() {
    Db.lambdaUpdate(User.class)
            .set(User::getBalance, 2000)
            .eq(User::getUsername, "Rose");
}

3.9、邏輯刪除

對于一些比較重要的數(shù)據(jù),我們往往會采用邏輯刪除的方案,即:

  • 在表中添加一個字段標(biāo)記數(shù)據(jù)是否被刪除
  • 當(dāng)刪除數(shù)據(jù)時把標(biāo)記置為true
  • 查詢時過濾掉標(biāo)記為true的數(shù)據(jù)

一旦采用了邏輯刪除,所有的查詢和刪除邏輯都要跟著變化,非常麻煩。

為了解決這個問題,MybatisPlus就添加了對邏輯刪除的支持。

注意,只有MybatisPlus生成的SQL語句才支持自動的邏輯刪除,自定義SQL需要自己手動處理邏輯刪除。

此時需要給表和實體類額外添加一個邏輯刪除字段

配置邏輯刪除字段

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 全局邏輯刪除的實體字段名(since 3.3.0,配置后可以忽略不配置步驟2)
      logic-delete-value: 1 # 邏輯已刪除值(默認(rèn)為 1)
      logic-not-delete-value: 0 # 邏輯未刪除值(默認(rèn)為 0)

開啟了邏輯刪除功能以后,我們就可以像普通刪除一樣做CRUD,基本不用考慮代碼邏輯問題。還是非常方便的。

注意: 邏輯刪除本身也有自己的問題,比如:

  • 會導(dǎo)致數(shù)據(jù)庫表垃圾數(shù)據(jù)越來越多,從而影響查詢效率
  • SQL中全都需要對邏輯刪除字段做判斷,影響查詢效率

因此,我不太推薦采用邏輯刪除功能,如果數(shù)據(jù)不能刪除,可以采用把數(shù)據(jù)遷移到其它表的辦法。

3.10、通用枚舉

一般User類中都會有一個Status代表狀態(tài)的屬性,像這種字段我們一般會定義一個枚舉,做業(yè)務(wù)判斷的時候就可以直接基于枚舉做比較。但是我們數(shù)據(jù)庫采用的是int類型,對應(yīng)的PO也是Integer。因此業(yè)務(wù)操作時必須手動把枚舉Integer轉(zhuǎn)換,非常麻煩。

因此,MybatisPlus提供了一個處理枚舉的類型轉(zhuǎn)換器,可以幫我們枚舉類型與數(shù)據(jù)庫類型自動轉(zhuǎn)換

定義枚舉類:

package com.itheima.mp.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;
@Getter
public enum UserStatus {
    NORMAL(1, "正常"),
    FREEZE(2, "凍結(jié)")
    ;
    @EnumValue
    private final int value;
    private final String desc;
    UserStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}

要讓MybatisPlus處理枚舉與數(shù)據(jù)庫類型自動轉(zhuǎn)換,我們必須告訴MybatisPlus,枚舉中的哪個字段的值作為數(shù)據(jù)庫值。 MybatisPlus提供了@EnumValue注解來標(biāo)記枚舉屬性:

配置枚舉處理類

mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

3.11、JSON類型處理器

數(shù)據(jù)庫的user表中有一個info字段,是JSON類型

格式為:{"age": 20, "intro": "佛系青年", "gender": "male"}

而一般類中都是用String類型去存儲的,

這樣一來,我們要讀取info中的屬性時就非常不方便。如果要方便獲取,info的類型最好是一個Map或者實體類。

而一旦我們把info改為對象類型,就需要在寫入數(shù)據(jù)庫時手動轉(zhuǎn)為String,再讀取數(shù)據(jù)庫時,手動轉(zhuǎn)換為對象,這會非常麻煩。

因此MybatisPlus提供了很多特殊類型字段的類型處理器,解決特殊字段類型與數(shù)據(jù)庫類型轉(zhuǎn)換的問題。例如處理JSON就可以使用JacksonTypeHandler處理器。

接下來,我們就來看看這個處理器該如何使用。

定義一個實體:

package com.itheima.mp.domain.po;
import lombok.Data;
@Data
public class UserInfo {
    private Integer age;
    private String intro;
    private String gender;
}

接下來,將User類的info字段修改為UserInfo類型,并聲明類型處理器:

四、插件功能

MybatisPlus提供了很多的插件功能,進(jìn)一步拓展其功能。目前已有的插件有:

  • PaginationInnerInterceptor:自動分頁
  • TenantLineInnerInterceptor:多租戶
  • DynamicTableNameInnerInterceptor:動態(tài)表名
  • OptimisticLockerInnerInterceptor:樂觀鎖
  • IllegalSQLInnerInterceptor:sql 性能規(guī)范
  • BlockAttackInnerInterceptor:防止全表更新與刪除

4.1、分頁插件

使用多個分頁插件的時候需要注意插件定義順序,建議使用順序如下:

  • 多租戶,動態(tài)表名
  • 分頁,樂觀鎖
  • sql 性能規(guī)范,防止全表更新與刪除

在未引入分頁插件的情況下,MybatisPlus是不支持分頁功能的,IServiceBaseMapper中的分頁方法都無法正常起效。 所以,我們必須配置分頁插件。

配置類:

package com.itheima.mp.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 MybatisConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        // 初始化核心插件
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分頁插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

測試:

@Test
void testPageQuery() {
    // 1.分頁查詢,new Page()的兩個參數(shù)分別是:頁碼、每頁大小
    Page<User> p = userService.page(new Page<>(2, 2));
    // 2.總條數(shù)
    System.out.println("total = " + p.getTotal());
    // 3.總頁數(shù)
    System.out.println("pages = " + p.getPages());
    // 4.數(shù)據(jù)
    List<User> records = p.getRecords();
    records.forEach(System.out::println);
}

到此這篇關(guān)于Mybatis-Plus超級實用的多種功能用法的文章就介紹到這了,更多相關(guān)MybatisPlus用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM---jstack分析Java線程CPU占用,線程死鎖的解決

    JVM---jstack分析Java線程CPU占用,線程死鎖的解決

    這篇文章主要介紹了JVM---jstack分析Java線程CPU占用,線程死鎖的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Java計算兩個時間段的差的實例詳解

    Java計算兩個時間段的差的實例詳解

    在本篇內(nèi)容中,我們給大家整理了關(guān)于Java計算兩個時間段的差的實例內(nèi)容,并做了詳細(xì)分析,有需要的朋友們學(xué)習(xí)下。
    2022-11-11
  • 利用Java+Selenium+OpenCV模擬實現(xiàn)網(wǎng)頁滑動驗證

    利用Java+Selenium+OpenCV模擬實現(xiàn)網(wǎng)頁滑動驗證

    目前很多網(wǎng)頁都有滑動驗證,目的就是防止不良爬蟲扒他們網(wǎng)站的數(shù)據(jù)。本文將介紹通過Java Selenium OpenCV解決網(wǎng)頁滑塊驗證,需要的可以參考一下
    2022-01-01
  • 從try-with-resources到ThreadLocal,優(yōu)化你的代碼編寫方式

    從try-with-resources到ThreadLocal,優(yōu)化你的代碼編寫方式

    這篇文章主要為大家介紹了從try-with-resources到ThreadLocal,優(yōu)化代碼的編寫方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Java解析JSON的六種方案

    Java解析JSON的六種方案

    這篇文章介紹了 6 種 JSON 解析方案,包括 Jackson、Gson、FastJSON、JsonPath、、手動解析,分別闡述了它們的功能特點、代碼示例、高級功能、優(yōu)缺點及適用場景,感興趣的小伙伴跟著小編一起來看看吧
    2025-01-01
  • SpringBoot啟動失敗的解決方法:A component required a bean of type ‘xxxxxxx‘ that could not be found.

    SpringBoot啟動失敗的解決方法:A component required a&nb

    這篇文章主要介紹了解決SpringBoot啟動失?。篈 component required a bean of type ‘xxxxxxx‘ that could not be found.,目前解決方法有兩種,一種是不注入bean的方式,另一種是使用@Component的方式,本文給大家詳細(xì)講解,需要的朋友可以參考下
    2023-02-02
  • RocketMQ設(shè)計之主從復(fù)制和讀寫分離

    RocketMQ設(shè)計之主從復(fù)制和讀寫分離

    這篇文章主要介紹了RocketMQ設(shè)計之主從復(fù)制和讀寫分離,RocketMQ提高消費避免Broker發(fā)生單點故障引起B(yǎng)roker上的消息無法及時消費,下文關(guān)于了RocketMQ的相關(guān)內(nèi)容,需要的小伙伴可以參考一下
    2022-03-03
  • 詳解Java8新特性Stream之list轉(zhuǎn)map及問題解決

    詳解Java8新特性Stream之list轉(zhuǎn)map及問題解決

    這篇文章主要介紹了詳解Java8新特性Stream之list轉(zhuǎn)map及問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • springboot使用消息中間件

    springboot使用消息中間件

    這篇文章主要介紹了springboot使用消息中間件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • springboot項目中使用JOSN解析庫的方法

    springboot項目中使用JOSN解析庫的方法

    JSON,全程是JavaScript Object Notation,是一種輕量級的數(shù)據(jù)交換格式,本文給大家介紹springboot項目中使用JOSN解析庫的相關(guān)知識,感興趣的朋友一起看看吧
    2025-06-06

最新評論

湟源县| 凌海市| 湖北省| 竹溪县| 平山县| 沁水县| 右玉县| 伊吾县| 翁牛特旗| 九寨沟县| 宁安市| 宣化县| 通道| 临颍县| 东兰县| 阿克陶县| 九龙城区| 盘山县| 翁源县| 姚安县| 雅安市| 东丰县| 滁州市| 资源县| 慈利县| 商洛市| 九龙城区| 新绛县| 界首市| 慈溪市| 庐江县| 上虞市| 通山县| 万源市| 于都县| 新乡市| 马尔康县| 黔江区| 滦南县| 南丰县| 吉木萨尔县|