天天看點

Mybatis-plus從入門到精通

作者:程式員的秃頭之路

1、什麼是MyBatis-Plus

MyBatis-Plus(簡稱MP)是一個基于MyBatis的增強工具,在MyBatis的基礎上對其進行擴充,用于簡化MyBatis操作,提高開發效率。它繼承了MyBatis原生的所有特性,并且添加了一些額外的功能,如自動化代碼生成、通用增删改查操作、條件構造器等。MyBatis-Plus是為了滿足日常開發中對簡單CRUD操作的需求而設計的,它的目标是讓開發人員專注于業務邏輯,而不是過多關注底層的資料庫操作。

MyBatis-Plus的主要特性包括:

1、 無侵入:MyBatis-Plus隻是作為MyBatis的一個插件,不會對MyBatis原有的功能産生影響,可以很容易地與已有的MyBatis項目內建。

2、 通用CRUD操作:MyBatis-Plus提供了一系列通用的CRUD方法,減少了手動編寫SQL和Mapper接口的工作量。通過繼承BaseMapper接口,你可以使用這些通用方法,進而實作基本的增删改查操作。

3、 條件構造器:MyBatis-Plus提供了一個強大的條件構造器,用于生成複雜的SQL查詢條件。這個條件構造器使得編寫查詢語句更加簡潔、易讀。

4、 分頁插件:MyBatis-Plus内置了一個功能強大的分頁插件,支援多種資料庫的分頁查詢。開發人員無需手動編寫分頁SQL,隻需簡單地調用API即可實作分頁功能。

5、 代碼生成器:MyBatis-Plus提供了一個自動化的代碼生成器,可以快速生成實體類、Mapper接口、Service接口和實作類、Controller類等。這極大地提高了開發效率,減少了手動編寫重複代碼的工作量。

6、 性能優化:MyBatis-Plus針對一些常見的性能問題進行了優化,例如SQL注入攻擊防護、緩存優化等。

總之,MyBatis-Plus是一個強大的MyBatis增強工具,它繼承了MyBatis的所有特性,并且提供了一些額外的功能,以提高開發效率和簡化CRUD操作。如果你已經在使用MyBatis,那麼MyBatis-Plus将是一個非常值得嘗試的工具。

官網位址
https://www.baomidou.com/           
Mybatis-plus從入門到精通

2、快速入門

2.1、Maven依賴 (pom.xml)

請将以下依賴項添加到項目的pom.xml檔案中:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.3.3</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
        <scope>provided</scope>
    </dependency>
</dependencies>           

2.2、application.yml配置檔案

以下是一個簡單的application.yml配置檔案示例,包含了MyBatis-Plus和MySQL資料庫的配置:

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: your_username
    password: your_password

mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml
  type-aliases-package: com.example.demo.entity
  configuration: 
  	log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 列印日志
  global-config:
    db-config:
      id-type: auto

logging:
  level:
    root: info           

在這個配置檔案中,我們設定了伺服器的端口号、資料源的驅動程式類名、資料庫URL、使用者名和密碼。我們還配置了MyBatis-Plus的映射檔案位置、類型别名包和全局配置,其中包括資料庫ID自動生成政策。

2.3、MySQL建表語句和初始化資料

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES
(1, 'Tom', 28, '[email protected]'),
(2, 'Jerry', 29, '[email protected]'),
(3, 'Spike', 30, '[email protected]');           

2.4、實體類 (User.java)

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

@Data
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}           

2.5、Mapper接口 (UserMapper.java)

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}           

2.6、Service接口 (UserService.java)

package com.example.demo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.entity.User;

public interface UserService extends IService<User> {
}           

2.7、Service實作類 (UserServiceImpl.java)

package com.example.demo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;

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

2.8、Controller類 (UserController.java)

package com.example.demo.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping
    public User createUser(@RequestBody User user) {
        userService.save(user);
        return user;
    }

    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getById(id);
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        user.setId(id);
        userService.updateById(user);
        return user;
    }

    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable Long id) {
        userService.removeById(id);
        return "User with ID " + id + " has been deleted.";
    }

    @GetMapping("/list")
    public List<User> listUsers() {
        return userService.list();
    }

    @GetMapping("/page")
    public IPage<User> pageUsers(@RequestParam(defaultValue = "1") int current,
                                  @RequestParam(defaultValue = "10") int size) {
        Page<User> userPage = new Page<>(current, size);
        return userService.page(userPage);
    }
}           

上面的代碼展示了基于MyBatis-Plus的增删改查示例。UserController類定義了建立、擷取、更新、删除使用者和分頁查詢的RESTful接口。具體來說,createUser、getUser、updateUser、deleteUser、listUsers和pageUsers方法分别負責建立使用者、根據ID擷取使用者、更新使用者、删除使用者、列出所有使用者和分頁查詢使用者。這些方法都依賴于注入的UserService實作類。

現在,你可以運作你的Spring Boot應用程式并通過RESTful API進行增删改查操作。

3、@TableId及主鍵政策

@TableId注解用于指定資料庫表的主鍵字段。這個注解可以放在實體類的字段上,以便MyBatis-Plus能識别哪個字段是資料庫表的主鍵。

@TableId注解有一個屬性type,它代表了主鍵政策。MyBatis-Plus支援以下幾種主鍵政策:

1、 IdType.AUTO:資料庫ID自增。這是預設的主鍵政策,适用于MySQL、PostgreSQL等支援自增主鍵的資料庫。在插入資料時,主鍵字段的值由資料庫自動生成。

2、 IdType.NONE:無主鍵政策。如果你的表沒有主鍵,可以使用這個選項。此時,插入資料時需要手動為主鍵字段設定值。

3、 IdType.INPUT:手動輸入。這種政策适用于那些需要手動為主鍵字段設定值的場景。在插入資料時,需要為主鍵字段提供一個值,否則會引發異常。

4、 IdType.UUID:全局唯一ID。在這種政策下,MyBatis-Plus會自動為主鍵字段生成一個UUID值。這種政策适用于那些需要全局唯一ID的場景,如分布式系統。

5、 IdType.ID_WORKER:分布式唯一ID。這種政策使用MyBatis-Plus内置的雪花算法(Snowflake Algorithm)生成分布式唯一ID。這個算法保證了在分布式環境中生成的ID是唯一的。

6、 IdType.ID_WORKER_STR:分布式唯一ID字元串。與IdType.ID_WORKER類似,但生成的ID會轉換為字元串格式。

7、 IdType.ASSIGN_ID:配置設定ID。這種政策使用MyBatis-Plus内置的ID生成器生成一個64位整數作為主鍵。生成的ID是全局唯一的,适用于分布式場景。

8、 IdType.ASSIGN_UUID:配置設定UUID。與IdType.UUID類似,但使用MyBatis-Plus内置的ID生成器生成UUID。

要自定義主鍵政策,你需要實作IdentifierGenerator接口,并在@TableId注解中指定自定義的實作類。以下是一個自定義主鍵政策的示例:

public class CustomIdGenerator implements IdentifierGenerator {

    @Override
    public Number nextId(Object entity) {
        // 實作你的自定義主鍵生成邏輯
        return yourCustomGeneratedId;
    }

    @Override
    public String nextUUID(Object entity) {
        // 實作你的自定義UUID生成邏輯
        return yourCustomGeneratedUuid;
    }
}           

然後,在實體類的主鍵字段上使用@TableId注解,并指定type為IdType.ASSIGN_ID或IdType.ASSIGN_UUID:

@TableId(value ="value", type = IdType.ASSIGN_ID, generator = "com.example.demo.CustomIdGenerator")
private Long id;           

在這個例子中,我們為主鍵字段id指定了IdType.ASSIGN_ID政策,并提供了自定義的CustomIdGenerator類來生成主鍵值。當插入新資料時,MyBatis-Plus将使用CustomIdGenerator提供的主鍵值。同樣,如果你想使用自定義的UUID生成政策,隻需将type屬性更改為IdType.ASSIGN_UUID即可。

這樣,你就可以根據自己的需求自定義主鍵政策,并在實體類中使用@TableId注解來指定該政策。

4、自動填充資料

MyBatis-Plus中的自動填充功能允許你在插入和更新操作中自動填充某些字段,例如建立時間、更新時間等。要實作自動填充功能,你需要建立一個類實作MetaObjectHandler接口,然後在實體類中使用@TableField注解指定要自動填充的字段。

MetaObjectHandler接口定義了兩個方法:insertFill和updateFill。insertFill方法用于在插入操作中自動填充字段,updateFill方法用于在更新操作中自動填充字段。以下是一個實作MetaObjectHandler接口的示例:

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

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

在這個例子中,我們建立了一個名為MyMetaObjectHandler的類,并實作了insertFill和updateFill方法。在insertFill方法中,我們使用strictInsertFill方法指定在插入操作時自動填充createTime和updateTime字段。在updateFill方法中,我們使用strictUpdateFill方法指定在更新操作時自動填充updateTime字段。

接下來,在實體類中使用@TableField注解指定要自動填充的字段:

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.time.LocalDateTime;

public class User {

    // ...其他字段

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;

    // ...getter和setter方法
}           

在這個例子中,我們為createTime字段指定了FieldFill.INSERT填充類型,這意味着在插入操作時将自動填充該字段。我們為updateTime字段指定了FieldFill.UPDATE填充類型,這意味着在更新操作時将自動填充該字段。

除了FieldFill.INSERT和FieldFill.UPDATE填充類型,MyBatis-Plus還支援以下填充類型:

1、 FieldFill.DEFAULT:預設填充類型,不進行自動填充。 2、 FieldFill.INSERT_UPDATE:在插入和更新操作中自動填充字段。

要使用FieldFill.INSERT_UPDATE填充類型,隻需将@TableField注解的fill屬性設定為FieldFill.INSERT_UPDATE即可。例如:

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime someField;           

這樣,在插入和更新操作中,MyBatis-Plus将自動填充someField字段。

總結一下,MyBatis-Plus的自動填充功能允許你在插入和更新操作中自動填充指定字段,如建立時間、更新時間等。要使用自動填充功能,你需要:

1、 建立一個實作MetaObjectHandler接口的類,并重寫insertFill和updateFill方法。 2、 在實體類中,使用@TableField注解指定要自動填充的字段,并設定相應的填充類型(FieldFill.DEFAULT、FieldFill.INSERT、FieldFill.UPDATE或FieldFill.INSERT_UPDATE)。

這樣,MyBatis-Plus就會根據指定的填充類型在插入和更新操作中自動填充相應字段。

5、樂觀鎖插件

樂觀鎖插件是MyBatis-Plus中的一個功能,用于在并發場景下保證資料的一緻性。樂觀鎖插件通過在更新操作時增加版本号或者其他辨別,以確定在多個線程同時更新同一條記錄時,隻有一個線程能夠成功執行更新。

以下是使用MyBatis-Plus樂觀鎖插件的示例:

5.1、首先,我們需要在Spring Boot配置類中注入樂觀鎖插件:

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("按需修改")
public class MybatisPlusConfig {

    /**
     * 舊版
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    /**
     * 新版
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}           

在這個例子中,我們建立了一個名為MybatisPlusConfig的配置類,并定義了一個optimisticLockerInterceptor Bean。這樣,樂觀鎖插件就會被自動添加到MyBatis-Plus中。

5.2、接下來,在實體類中為某個字段添加@Version注解,以表示這個字段用于存儲版本資訊。通常,這個字段是一個整數或者長整數類型,用于記錄資料的修改次數。

import com.baomidou.mybatisplus.annotation.Version;
import java.io.Serializable;

public class User implements Serializable {

    // ...其他字段

    @Version
    private Integer version;

    // ...getter和setter方法
}           

在這個例子中,我們為version字段添加了@Version注解,表示這個字段将用于存儲版本資訊。

5.3、現在,你可以正常地執行更新操作。當使用MyBatis-Plus的更新方法時,樂觀鎖插件會自動處理版本号的遞增和校驗。

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public void updateUser(Long userId, String newName) {
        User user = userMapper.selectById(userId);
        user.setName(newName);
        userMapper.updateById(user);
    }
}           

在這個例子中,我們建立了一個UserService類,并定義了一個updateUser方法。這個方法首先根據ID查詢使用者,然後修改使用者的名稱,并調用userMapper.updateById(user)方法執行更新操作。在這個過程中,樂觀鎖插件會自動處理版本号的遞增和校驗。

這樣,通過使用MyBatis-Plus的樂觀鎖插件,你可以在并發場景下保證資料的一緻性。隻需簡單地在實體類中添加@Version注解并注入樂觀鎖插件,即可實作這個功能。

6、其他插件(如:邏輯删除、分頁檢視...)檢視官網

官網位址
https://www.baomidou.com/           

7、增删改查常用方法

MyBatis-Plus提供了一系列常用的增删改查方法,大大簡化了對資料庫表的操作。以下是一些常用方法的介紹:

7.1、插入(Insert)

  • int insert(T entity):插入一條記錄。傳入的實體類對象entity中的非空字段會被插入到資料庫表中。傳回值為受影響的行數。

7.2、删除(Delete)

  • int deleteById(Serializable id):根據主鍵ID删除一條記錄。傳回值為受影響的行數。
  • int delete(Wrapper<T> queryWrapper):根據條件删除記錄。queryWrapper為查詢條件。傳回值為受影響的行數。
  • int deleteBatchIds(Collection<? extends Serializable> idList):根據主鍵ID批量删除記錄。idList為主鍵ID集合。傳回值為受影響的行數。

7.3、更新(Update)

  • int updateById(T entity):根據主鍵ID更新一條記錄。傳入的實體類對象entity中的非空字段會被更新到資料庫表中。傳回值為受影響的行數。
  • int update(T entity, Wrapper<T> updateWrapper):根據條件更新記錄。entity為要更新的字段值,updateWrapper為更新條件。傳回值為受影響的行數。

7.4、查詢(Select)

  • T selectById(Serializable id):根據主鍵ID查詢一條記錄。傳回查詢到的記錄對象。
  • List<T> selectBatchIds(Collection<? extends Serializable> idList):根據主鍵ID批量查詢記錄。idList為主鍵ID集合。傳回查詢到的記錄清單。
  • List<T> selectList(Wrapper<T> queryWrapper):根據條件查詢記錄清單。queryWrapper為查詢條件。傳回查詢到的記錄清單。
  • List<Map<String, Object>> selectMaps(Wrapper<T> queryWrapper):根據條件查詢記錄,并将結果轉換為Map清單。queryWrapper為查詢條件。傳回查詢到的記錄清單,每個記錄為一個Map對象。
  • T selectOne(Wrapper<T> queryWrapper):根據條件查詢一條記錄。queryWrapper為查詢條件。傳回查詢到的記錄對象。注意:當查詢結果多于一條時,該方法會抛出異常。
  • int selectCount(Wrapper<T> queryWrapper):根據條件查詢記錄數量。queryWrapper為查詢條件。傳回查詢到的記錄數量。

這些方法都是基于MyBatis-Plus提供的BaseMapper<T>接口定義的,你隻需要在你的Mapper接口中繼承BaseMapper<T>,即可使用這些方法。例如:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;

public interface UserMapper extends BaseMapper<User> {
}           

8、條件構造器Wrapper(常用)

MyBatis-Plus中的條件構造器Wrapper(如QueryWrapper<T>和UpdateWrapper<T>)提供了一系列常用的條件構造方法,幫助你輕松建構複雜的查詢和更新條件。以下是一些常用方法的介紹:

8.1、基本條件

  • eq(String column, Object val):等于,用于構造“column = val”的條件。
  • ne(String column, Object val):不等于,用于構造“column <> val”的條件。
  • gt(String column, Object val):大于,用于構造“column > val”的條件。
  • ge(String column, Object val):大于等于,用于構造“column >= val”的條件。
  • lt(String column, Object val):小于,用于構造“column < val”的條件。
  • le(String column, Object val):小于等于,用于構造“column <= val”的條件。
  • between(String column, Object val1, Object val2):範圍,用于構造“column BETWEEN val1 AND val2”的條件。
  • notBetween(String column, Object val1, Object val2):非範圍,用于構造“column NOT BETWEEN val1 AND val2”的條件。
  • like(String column, Object val):模糊查詢,用于構造“column LIKE %val%”的條件。
  • notLike(String column, Object val):非模糊查詢,用于構造“column NOT LIKE %val%”的條件。

8.2、常用條件組合

  • and(String sql):與,用于連接配接兩個條件,如“condition1 AND condition2”。
  • or(String sql):或,用于連接配接兩個條件,如“condition1 OR condition2”。

8.3、嵌套條件

  • and(Consumer<Param> consumer):與,用于構造嵌套條件,如“condition1 AND (condition2 OR condition3)”。
  • or(Consumer<Param> consumer):或,用于構造嵌套條件,如“condition1 OR (condition2 AND condition3)”。

8.4、排序

  • orderByAsc(String... columns):升序排序,用于構造“ORDER BY column1 ASC, column2 ASC”等排序條件。
  • orderByDesc(String... columns):降序排序,用于構造“ORDER BY column1 DESC, column2 DESC”等排序條件。

以下是一個使用條件構造器Wrapper的查詢示例:

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {
    @Autowired
private UserMapper userMapper;

public List<User> getUsersByNameAndAge(String name, Integer minAge, Integer maxAge) {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("name", name)
                .ge("age", minAge)
                .le("age", maxAge)
                .orderByAsc("age");
    
    return userMapper.selectList(queryWrapper);
	}
}           

在這個示例中,我們建立了一個UserService類,并實作了一個getUsersByNameAndAge方法。這個方法使用QueryWrapper構造了一個查詢條件,用于查找名字包含name,年齡在minAge和maxAge之間并按年齡升序排列的使用者。通過調用userMapper.selectList(queryWrapper),我們可以擷取符合條件的使用者清單。

總之,MyBatis-Plus中的條件構造器Wrapper提供了一系列常用的條件構造方法,幫助你輕松建構複雜的查詢和更新條件。通過使用QueryWrapper和UpdateWrapper,你可以友善地構造各種條件,并将這些條件應用到MyBatis-Plus的增删改查方法中。

繼續閱讀