Detailed integration of SpringBoot and mybatis plus and the most commonly used practical tutorials (get started quickly)

Posted by cshinteractive on Tue, 21 Dec 2021 03:13:16 +0100

preface
Mybatis plus (MP for short) is an enhanced tool for Mybatis to simplify development and improve efficiency. Mybatis has all of them. It is based on Mybatis: it only makes enhancements without changes, and has powerful functions and is very easy to use (strongly recommended)

  1. This tutorial will try to simulate the use of real development environment, which is relatively complete and covers the most commonly used processes of mybatis plus
  2. maven dependent jar s used in this project are all newer versions. I also use them myself. I don't have to worry about the version dependency problems related to mp and druid. I can use them safely

1: First create a student table: t_student

CREATE TABLE `t_student` (
  `id` bigint(20) NOT NULL,
  `name` varchar(16) NOT NULL COMMENT 'full name',
  `gender` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'Gender (1 male, 2 female, 0 unknown)',
  `major_id` int(11) NOT NULL COMMENT 'Major id',
  `phone` varchar(16) NOT NULL COMMENT 'cell-phone number',
  `create_time` datetime NOT NULL COMMENT 'Creation time',
  `update_time` datetime NOT NULL COMMENT 'Update time',
  `del_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT 'Delete tag (0 not deleted, 1 deleted)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Student list';
  1. The student table id simulated here is of bigint type and is not self incremented (generally, tables with a large amount of data do not use self incremented primary keys)
  2. There is a create that exists in almost every table_ time,update_time, and a logical deletion flag del_flag, which gives a default value of 0 for pseudo deletion. These three fields are generally regarded as a whole, because they are fixed and can be used in each table

2: Create MP demo project and configure dependency and environment

1. maven dependency

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--  spring relevant jar package -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Database connection jar package -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

        <!-- pageHelper Pagination (Note: to avoid and mybatis-plus (conflicts, some dependencies need to be excluded) -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.3.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis-spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Essential Kit -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.17</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
  1. Above, I only introduced some jar packages used in this case. If there is any other need, you can import them by yourself
  2. The version of mp is 3.4 2. druid is used for connection pool, version 1.2 6. They are relatively new and compatible
  3. As for the paging function, in fact, mp also provides paging plug-ins for use, but I really don't like to use the built-in ones. Because they are troublesome and invasive to code, I prefer to use pagehelper for paging, which is more convenient

2. Create project structure package

The handler package is the processor package, the po package is the entity class package, the mapper is the mapper interface of mybatis, and the service is the service interface + impl implementation class. As for the result package, it is my custom unified interface return package. You can have your own

3. application.yml

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/my_test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver # Note: if your MySQL jar package is imported with a version above 8.0, the driver is: com mysql. cj. jdbc. Driver
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 5 # Number of physical connections established during initialization
      min-idle: 5 # Minimum number of connection pools
      max-active: 100 # Maximum number of connection pools
      max-wait: 60000 # Maximum wait time to get a connection
      stat-view-servlet:
        login-username: admin # Configure monitoring page access login name
        login-password: admin # Configure monitoring page access password
      filter:
        stat:
          log-slow-sql: true # Enable slow sql query monitoring
          slow-sql-millis: 1 # Slow SQL execution time
      pool-prepared-statements: true
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      max-open-prepared-statements: 20
      validation-query: SELECT 1 FROM DUAL

  application:
    name: MP-Demo

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true # Turn on the hump law
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # If it is released, SQL printing will be enabled (that is, every SQL operation database will be printed on the console. It is recommended to close it after being proficient, otherwise there will be a lot of logs)
  type-aliases-package: com.taoge.po # Entity class package path
  mapper-locations: classpath*:mapper/**/*Mapper.xml # xml file directory for storing sql statements
  global-config:
    db-config:
      logic-delete-field: delFlag # The name of the entity field to be deleted by global logic (it seems that the field name filled in here can also be used)
      logic-delete-value: 1 # Logical deleted value (1 indicates deleted)
      logic-not-delete-value: 0 # Logical undeleted value (default is 0, indicating undeleted)

# Paging plug-in PageHelper configuration
pagehelper:
  helper-dialect: mysql
  pageSizeZero: true
  params: count=countSql
  reasonable: true
  support-methods-arguments: true

Here we mainly talk about the configuration of mybatis plus: in fact, it is very similar to the previous mybatis configuration, such as enabling hump rule, entity class path and xml path.
As for the log impl configuration, it is actually to print the execution sql of mp. I suggest that you start it when you first use it, and note this line after you are proficient in it, so that there will be fewer logs.
Focus on the global config configuration. The configuration here is the global logical deletion delFlag, that is, pseudo deletion. When mp queries automatically, it will automatically add del after the where statement_ Flag = 0, filter the deleted data, and add del automatically when updating and deleting_ Flag = 0.

4. MPApplication

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.taoge.mapper") // Scan mapper interface package
@SpringBootApplication
public class MPApplication {

    public static void main(String[] args) {
        SpringApplication.run(MPApplication.class, args);
    }
}

5. Configure the auto stuffer

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

import java.time.LocalDateTime;

/**
 * Custom mybatis plus population processor
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    // Default policy: if the attribute has a value, it will not be overwritten. If the filling value is null, it will not be filled

    private static final String CREATE_TIME = "createTime";
    private static final String UPDATE_TIME = "updateTime";

    /**
     * The values automatically filled in during insert (here are generally create_time and update_time)
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        if (metaObject.hasGetter(CREATE_TIME) && metaObject.hasGetter(UPDATE_TIME)) { // The entity class has a get method, which is the field
            LocalDateTime localDateTime = LocalDateTime.now();
            log.info("[insertFill]localDateTime={}", localDateTime.toString());
            this.strictInsertFill(metaObject, CREATE_TIME, () -> localDateTime, LocalDateTime.class); // Starting version 3.3.1 3 (recommended)
            this.strictInsertFill(metaObject, UPDATE_TIME, () -> localDateTime, LocalDateTime.class); // Starting version 3.3.1 3 (recommended)
        }
    }

    /**
     * The value automatically filled in during update (update is only for update_time)
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        if (metaObject.hasGetter(UPDATE_TIME)) {
            LocalDateTime localDateTime = LocalDateTime.now();
            log.info("[updateFill]localDateTime={}", localDateTime.toString());
            this.strictUpdateFill(metaObject, UPDATE_TIME, () -> localDateTime, LocalDateTime.class); // Starting version 3.3.1 3 (recommended)
        }
    }
}
  1. We want create in the table_ time,update_ The time field can be automatically filled in when adding or updating. There is no need to set it manually, so the above automatic filler is configured
  2. In fact, the stuffers demonstrated here can be richer. For example, createBy and updateBy, i.e. creator and updater, can be added according to actual needs
  3. The time type here does not use the Date type, but the LocalDateTime type in jdk8 (of course, the Date type can also be used)

6. Create entity class
(1) Create a new base package under po package, and then create BaseEntity

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;

/**
 * @author rlt
 * @date 2021/12/15 14:57
 */
@Getter
@Setter
public abstract class BaseEntity {

    /** Creation time */
    @TableField(fill = FieldFill.INSERT) // Insert autofill
    private LocalDateTime createTime;

    /** Update time */
    @TableField(fill = FieldFill.INSERT_UPDATE) // Auto fill on insert or update
    private LocalDateTime updateTime;

    /** Delete tag (0 not deleted, 1 deleted) */
//    @TableLogic / / this annotation indicates that the field is a logically deleted field (this annotation is omitted because the current mp version is 3.4.2. This annotation can be omitted from version 3.3.0)
    private Integer delFlag;
}

Since the automatic filler has been configured above, the corresponding annotation should be added to the field when using here, so there is no need to manually set the value when inserting the update

(2) Create a new Student class under po package and inherit BaseEntity

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.taoge.po.base.BaseEntity;
import lombok.Data;

import java.io.Serializable;

/**
 * Student po
 */
@Data
@TableName(value = "t_student") // Specify the corresponding table name in the database
public class Student extends BaseEntity implements Serializable {

    private static final long serialVersionUID = 3819669465179936254L;

    // @TableId(type = IdType.AUTO): table primary key id annotation. AUTO indicates that the id is self incremented
    // @TableField(value = "major_id"): table field annotation. Value indicates the corresponding field in the table. However, this annotation may not be added as long as the table field naming is standardized and the hump in the entity class is named

    /** Student id */
//    @TableId(type = IdType.AUTO) / / if your table primary key id is self incremented, add this line of annotation. My id here is not self incremented, so don't add @ TableId annotation
    private Long id;

    /** full name */
    private String name;

    /** Gender: 1 male, 2 female, 0 unknown */
    private Integer gender;

    /** Professional id */
//    @TableField(value = "major_id") / / specify the corresponding field in the table. For convenience, this annotation can be omitted
    private Integer majorId;

    /** cell-phone number */
    private String phone;

    //======Here are the additional fields I added=========

    /** Discipline name */
    @TableField(exist = false) // Non table field (this kind of field must be annotated with @ TableField. exist defaults to true. If false, it means non data table field)
    private String majorName; // This field will not be included in the automatic query of mybatis plus, but it can be mapped when you customize the multi table query sql in xml
}

7. Create mapper interface: StudentMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.taoge.po.Student;

public interface StudentMapper extends BaseMapper<Student> {
}
  1. mapper interface directly inherits mp's BaseMapper interface. studentMapper is the corresponding class, which is Student
  2. There is no need to add @ mapper and @ Repository annotations on the interface, because the entire mapper package path has been scanned on the startup class

8. Create service interface and implementation class
(1) StudentService interface

import com.baomidou.mybatisplus.extension.service.IService;
import com.taoge.po.Student;

import java.util.List;

public interface StudentService extends IService<Student> {
}

The service interface directly inherits the IService interface of mp, and also specifies the class as Student, so you can use the methods provided in IService

(2) Implementation class

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.taoge.mapper.StudentMapper;
import com.taoge.po.Student;
import com.taoge.service.StudentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
}

This is to inherit ServiceImpl and specify the corresponding mapper and class, so that the automatic curd operation is completed

3: Create test Controller

1. Add interface

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.taoge.mapper.StudentMapper;
import com.taoge.po.Student;
import com.taoge.result.CodeMsg;
import com.taoge.result.Result;
import com.taoge.service.StudentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author rlt
 * @date 2021/12/15 15:59
 */
@Slf4j
@RestController
@RequestMapping("/student")
@RequiredArgsConstructor // lombok annotation: it can replace @ Autowired, but final must be added (in fact, it is injected through the constructor)
public class StudentController {

    // For demonstration, I have injected both service and mapper here. In actual development, only one service needs to be injected, mainly to introduce the operation differences of mapper pairs of service
    // In fact, the functions of service and mapper are basically the same. Some functions of service and mapper also exist, but there are differences in method names when they are dual-use
    // The mapper is called inside the method in the service. You can click in to see the source code
    // In practice, you can customize some methods in the service and call mapper in serviceImpl. When you understand the use of mybatisplus, you can play it freely

    private final StudentService studentService;
    private final StudentMapper studentMapper;

    /**
     * newly added
     */
    @PostMapping("/add")
    public Result add() {
        // service demo NEW
        Student student = new Student();
        student.setName("Zhang San");
        student.setGender(1);
        student.setMajorId(1);
        student.setPhone("18300001111");
        boolean save = studentService.save(student);
        // mapper demo NEW
        Student student1 = new Student();
        student1.setName("Xiao Fang");
        student1.setGender(2);
        student1.setMajorId(1);
        student1.setPhone("18300002222");
        int insert = studentMapper.insert(student1); // The above save also calls insert internally, but the name is different
        log.info("[add]save={}, insert={}", save, insert);
        // Batch insert
        Student student2 = new Student();
        student2.setName("the other woman");
        student2.setGender(2);
        student2.setMajorId(2);
        student2.setPhone("18300003333");
        Student student3 = new Student();
        student3.setName("Xiao Ming");
        student3.setGender(1);
        student3.setMajorId(1);
        student3.setPhone("18300004444");
        List<Student> studentList = new ArrayList<>();
        studentList.add(student2);
        studentList.add(student3);
        studentService.saveBatch(studentList); // saveBatch can only be called with service
        return Result.success(save && insert == 1);
    }
}

Since the primary key id of the student table is not self incrementing, although I don't have setId here, mybatis plus will automatically generate a long id for us. Of course, you can also use the id generation strategy in your project to generate it, and then manually setId, such as snowflake algorithm to generate id, which will be better

Request with postman: http://localhost:8080/student/add , the debug process is as follows:


2. Query interface

   /**
     * query
     */
    @GetMapping("/query/{id}")
    public Result query(@PathVariable("id") Long id) {
        // 1. Query by id
        Student student = studentService.getById(id);
//        student = studentMapper.selectById(id); //  Equivalent to the above line
        log.info("[query]student={}", JSON.toJSONString(student));

        // 2. Query all (pagehelper paging can be added when querying the list. It will not be demonstrated here. Try it yourself. It's very simple)
        List<Student> studentAllList = studentService.list(); // Or write it list(null), the two are the same
//        List<Student> studentAllList = studentMapper. selectList(null); //  Equivalent to the above writing
        log.info("[query]studentAllList={}", JSON.toJSONString(studentAllList));

        // 3. Query by query

        // Condition constructor (not recommended): query name = Zhang San
        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", "Zhang San"); // Conditional query (eq is equal to, i.e. name = 'Zhang San')
        queryWrapper.select("id", "name", "major_id"); // Query the specified fields (if this row is not added, all fields will be queried by default. Note: the fields here are filled in the fields in the table)
        Student student1 = studentService.getOne(queryWrapper); // getOne: means to query only one result
//        Student student1 = studentMapper.selectOne(queryWrapper);  Equivalent to the above line
        log.info("[query]student1={}", JSON.toJSONString(student1)); // Note: since I added the specified field query above, only these fields have values

        // lambda query builder (recommended): query the list of students with major_id=1
        LambdaQueryWrapper<Student> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Student::getMajorId, 1); // Condition: where major_id = 1 (if multi condition query can be continued,. eq can be added in this way)
        lambdaQueryWrapper.select(Student::getId, Student::getName, Student::getGender); // I just want to check these three fields
        lambdaQueryWrapper.orderByDesc(Student::getCreateTime); // Sorting: order by create_time desc
        List<Student> studentList = studentService.list(lambdaQueryWrapper);
        log.info("[query]studentList={}", JSON.toJSONString(studentList));

        // Here is another customized method in the service: query professional 1 and gender female
        List<Student> studentList2 = studentService.getByMajorIdAndGender(1, 2);
        log.info("[query]studentList2={}", JSON.toJSONString(studentList2));

        // The above can be done with service, and the same can be done with mapper, because mapper is still used to query in the service, and you can try it yourself
        // There are more commonly used special queries, such as fuzzy queries, which are introduced at the end
        return Result.success(true);
    }

StudentServiceImpl: add the following method

    // Here, you can inject mapper to operate, or you can use mp's baseMapper to operate (because mapper inherits baseMapper)
    // If you have complex sql or custom sql, follow the operation of native mybatis, write the interface in mapper and write sql in xml
    private final StudentMapper studentMapper;

    @Override
    public List<Student> getByMajorIdAndGender(Integer majorId, Integer gender) {
        // Similarly, use LambdaQueryWrapper
        LambdaQueryWrapper<Student> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Student::getMajorId, majorId).eq(Student::getGender, gender);

        // Because StudentService inherits IService, you can directly use the methods in service or mapper
        // Operate with service
        List<Student> serviceList = this.list(queryWrapper); // The methods in IService can be directly used in the implementation class here
        // Operate with mapper
        List<Student> mapperList = baseMapper.selectList(queryWrapper); // Here you can also use: studentmapper selectList(queryWrapper)
        log.info("[getByMajorIdAndGender]serviceList={}", serviceList);
        log.info("[getByMajorIdAndGender]mapperList={}", mapperList); // The two queries must be the same
        return mapperList;
    }

The above can be done with service, and the same can be done with mapper, because the mapper is still used to query in the service, and you can try it yourself. In addition, there are more commonly used special queries, such as fuzzy queries, which are introduced at the end

Request with postman: http://localhost:8080/student/query/1472863272568754178

3. Update interface

   /**
     * to update
     */
    @PostMapping("/update/{id}")
    public Result update(@PathVariable("id") Long id) {
        // 1. Update according to id
        Student student = new Student();
        student.setId(id);
        student.setName("Zhang Sansan"); // Update the name as Zhang Sansan according to the id
        boolean updateById = studentService.updateById(student); // updateTime is automatically populated
        log.info("[update]updateById={}", updateById);

        // 2. Update the specified conditions: change the major whose name = Zhang Sansan to 3
        LambdaUpdateWrapper<Student> updateWrapper = new LambdaUpdateWrapper<>(); // Create lambda Updater
        updateWrapper.set(Student::getMajorId, 3); // set in the updater is the field to be updated and the final result
        updateWrapper.set(Student::getUpdateTime, DateUtil.toLocalDateTime(new Date())); // You need to manually set Updatetime here, because the updated field values here are customized by us
        updateWrapper.eq(Student::getName, "Zhang Sansan"); // eq is the update condition, that is, sql is set major_id = 3 where name = 'Zhang Sansan'
        boolean update = studentService.update(updateWrapper);
        log.info("[update]update={}", update);

        // Here's a point. If I want to change a field in the table from non null to null, I can't use updateById and it won't take effect
        // It is recommended to update the specified fields. Of course, it can also be implemented with native manual sql statements
        // For example, in the above, I now want to change the major of name = Zhang Sansan to null, and then change it to updatewrapper set(Student::getMajorId, null)
        return Result.success(updateById && update);
    }

Note: when specifying the condition update, the automatic filling of updateTime will fail. Because the update is customized, mp does not fill, so setUpdateTime is added manually

postman request: http://localhost:8080/student/update/1472863272568754178


4. Delete interface

   /**
     * delete
     */
    @PostMapping("/delete/{id}")
    public Result delete(@PathVariable("id") Long id) {
        // Generally, you can check before deleting, and then delete if it is not empty
        Student student = studentService.getById(id);
        if (null == student) {
            return Result.error(CodeMsg.DELETE_FAIL);
        }

        // Note: removeById means to delete according to id (common), and batch delete according to id. the method is removeByIds
        // However, if the yml is configured with pseudo delete, the removeById changes from the original delete to update, that is, delete_ The flag field value is changed to 1

        // Note: since pseudo deletion is currently configured in yml, if you use the mp deletion interface, there will be a small bug: Although the data is deleted, it is updated_ Time does not automatically fill in the change, or the original time
        // In order to avoid this bug, since it is a pseudo deletion, I suggest to update all and update del manually_ Flag and update_time, or manually write the sql implementation in xml

        // 1. Delete according to id (update the specified field according to id)
        LambdaUpdateWrapper<Student> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Student::getDelFlag, 1);
        updateWrapper.set(Student::getUpdateTime, DateUtil.toLocalDateTime(new Date()));
        updateWrapper.eq(Student::getId, id);
        boolean update = studentService.update(updateWrapper);
        log.info("[delete]update={}", update);

        // 2. Condition deletion: delete female students with major = 5 (similarly, pseudo deletion follows the specified condition update)
        updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Student::getDelFlag, 1);
        updateWrapper.set(Student::getUpdateTime, DateUtil.toLocalDateTime(new Date()));
        updateWrapper.eq(Student::getMajorId, 5);
        updateWrapper.eq(Student::getGender, 2);
        boolean update1 = studentService.update(updateWrapper); // Since there is no data with professional id=5, false is returned
        log.info("[delete]update1={}", update1);

//        //If your watch doesn't have a similar del_ If the flag field is true deletion directly, there are two types of deletion:
//        //Delete by id
//        studentService.removeById(id); //  Or studentmapper deleteById(id)
//        //Delete according to condition
//        LambdaQueryWrapper<Student> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(Student::getMajorId, 5);
//        queryWrapper.eq(Student::getGender, 2);
//        studentService.remove(queryWrapper);
        return Result.success(update, "Delete succeeded");
    }

postman access: http://localhost:8080/student/delete/1472863272568754178

5. Introduction to special query
First change the deleted delFlag of Zhang Sansan to 0 to facilitate the test

   /**
     * Introduction to special query (I will use service and lambda query to demonstrate here)
     */
    @GetMapping("/query2")
    public Result query2() {
        // 1. Fuzzy query: students with three names
        LambdaQueryWrapper<Student> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(Student::getName, "three"); // name like '% three%' (there is also an uncommon notLike)
//        queryWrapper.likeLeft(Student::getName, "three")// name like '% three'
//        queryWrapper.likeRight(Student::getName, "three")// name like 'three%'
        queryWrapper.orderByDesc(Student::getCreateTime); // Reverse order output
        List<Student> likeList = studentService.list(queryWrapper);
        log.info("[query2]likeList={}", JSON.toJSONString(likeList));

        // 2. Range query: greater than or less than
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.gt(Student::getCreateTime, "2021.12.20 17:38:00"); // gt means greater than: create_ time > 2021.12. 17 06:00:00
        queryWrapper.lt(Student::getCreateTime, "2021.12.25 22:00:00"); // lt means less than: create_ time < 2021.12. 18 22:00:00
        List<Student> gltList = studentService.list(queryWrapper);
        // There are also: ge (greater than or equal to > =), le (less than or equal to < =), ne (not equal to < >), between (between two values). Just draw the ladle according to the gourd. No demonstration
        log.info("[query2]gltList={}", JSON.toJSONString(gltList));

        // 3. Group query: groupBy
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.groupBy(Student::getMajorId);
        List<Student> groupList = studentService.list(queryWrapper);
        log.info("[query2]groupList={}", JSON.toJSONString(groupList));

        // 4. in query
        queryWrapper = new LambdaQueryWrapper<>();
        List<String> list = new ArrayList<>();
        list.add("Zhang San");
        list.add("Li Si");
        queryWrapper.in(Student::getName, list); // There is also notIn
        List<Student> inList = studentService.list(queryWrapper);
        log.info("[query2]inList={}", JSON.toJSONString(inList));

        // 5. Empty query (not commonly used)
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNull(Student::getName); // name is null, and there must be isNotNull
        List<Student> nullList = studentService.list(queryWrapper);
        log.info("[query2]nullList={}", JSON.toJSONString(nullList));

        // 6. Dynamic query
        // No matter eq, gt, in and so on, there is a Boolean parameter at the beginning of execution. If it is not passed, it is true by default
        // For all the queries above, we didn't pass this parameter. In fact, it is automatically set to true for us. Click to see the source code
        // The meaning of this Boolean parameter: if it is true, it means to bring this condition. If it is false, it will ignore this condition. In fact, it is used for dynamic SQL
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(false, Student::getName, "Zhang San"); // If false is set here, this setting will not take effect. It means that without this line, all students will still be queried
        queryWrapper.eq(nullList.size() > 0, Student::getMajorId, 1); // If nullList has data, this setting will take effect and students with major = 1 will be queried
        List<Student> dynamicList = studentService.list(queryWrapper);
        log.info("[query2]dynamicList={}", JSON.toJSONString(dynamicList));
        return Result.success(true);
    }

postman access: http://localhost:8080/student/query2




The above is the most commonly used tutorial of mybatis plus. All the codes have passed my actual measurement. There is no problem. One thing to note is pseudo deletion. If you don't have a del for each table_ The flag field can be manually implemented without global logical deletion configuration in the yml file. For example, when querying, manually add the condition: delFlag = 0, which is the same as when deleting. In short, it can be used flexibly after familiarity.

Topics: Java Spring Boot mybatis-plus