SpringBoot と Mybatis-Plus の詳細な統合と一般的な実践的なチュートリアル (pagehelper ページング + 自動入力失敗処理の更新)

はじめにMyBatis -
Plus (略して MP) は、開発を簡素化し、効率を向上させるために、中国の Baomidou チームによって開発された MyBatis 拡張ツールです。)

  1. このチュートリアルでは、実際の開発環境の使用をシミュレートします。この環境は比較的完全で、mybatis-plus の最も一般的に使用されるプロセスをカバーしています。
  2. このプロジェクトで使用されている Maven の依存関係 jar は新しいバージョンです。私自身も使用しています。mp やその他の関連するバージョンの依存関係については心配する必要はありません。安心して使用できます。
  3. mybatis-plus の導入後は、mybatis-springboot の依存関係を導入する必要がなくなり、マッパー インターフェイスの記述と XML でのカスタム SQL の記述もサポートされます (オリジナルを変更しないでください)。

1: まず、学生テーブル t_student を作成します。

CREATE TABLE `t_student` (
  `id` bigint(20) NOT NULL,
  `name` varchar(16) NOT NULL COMMENT '姓名',
  `gender` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别(1男,2女,0未知)',
  `major_id` int(11) NOT NULL COMMENT '所属专业id',
  `phone` varchar(16) NOT NULL COMMENT '手机号',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  `del_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT '删除标记(0未删除,1已删除)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';
  1. ここでシミュレートされた学生テーブル ID は bigint 型であり、自動インクリメントされません (一般に、大量のデータを含むテーブルに自動インクリメントの主キーを使用することはお勧めできません)。
  2. ほとんどすべてのテーブルに存在する create_time、update_time、および擬似削除のデフォルト値 0 を持つ論理削除フラグ del_flag があり、これら 3 つのフィールドは固定されているため、一般に全体として見なされます。

2: MP-Demo プロジェクトを作成し、依存関係と環境を構成する

1.Mavenの依存関係

    <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相关jar包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 数据库连接jar包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

        <!-- pageHelper分页(注意:为避免和mybatis-plus的冲突,需排除部分依赖) -->
        <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>

        <!-- 必备工具包 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </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. 上記では、このケースで使用されるいくつかの jar パッケージを紹介しただけです。他に必要な場合は、自分で再インポートできます。
  2. springboot バージョンは 2.5.2、mp バージョンは 3.4.2、接続プールは druid を使用せず、デフォルトの hikari が使用されます。
  3. ページング機能については、実は mp にもページングプラグインが用意されていて、それを利用できるのですが、私は組み込みのものを使いたくなくて、使うのが面倒でコードに煩わしさを感じるので、今でも使い続けています。ページングには pagehelper を使用することを選択します。これはより便利です

2. プロジェクト構造パッケージを作成するプロジェクト構造

handlerパッケージはプロセッサパッケージ、poパッケージはエンティティクラスパッケージ、マッパーはmybatisのマッパーインターフェース、サービスはサービスインターフェース+impl実装クラスで、結果パッケージは私のカスタム統一インターフェースです。返品パッケージ。ご自身のものでもお気軽に

3.application.yml

server:
  port: 8080

spring:
  application:
    name: MP-Demo

  datasource:
    url: jdbc:mysql://127.0.0.1:3306/my_test?serverTimezone=Asia/Shanghai&useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimum-idle: 5
      maximum-pool-size: 15
      auto-commit: true
      idle-timeout: 30000
      pool-name: ${
    
    spring.application.name}-HikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: SELECT 1

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true # 开启驼峰法则(可省略此行,默认已开启)
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启SQL打印(就是每次操作数据库都会在控制台打印出来SQL语句,建议使用熟练以后注掉此行,不然日志很多)
  type-aliases-package: com.taoge.po # 实体类包路径(也可省略此行,不用配置)
  mapper-locations: classpath*:mapper/**/*Mapper.xml # 存放sql语句的xml文件目录
  global-config: # 此项是否配置根据实际项目来
    db-config:
      logic-delete-field: delFlag # 全局逻辑删除的实体字段名(这里填表字段名好像也可以)
      logic-delete-value: 1 # 逻辑已删除值(为1,表示已删除)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为0, 表示未删除)

# 分页插件PageHelper(当reasonable=false时,若当前页超过最大页数则不返回数据,为true则依然会返回最后一页数据)
pagehelper:
  helper-dialect: mysql
  pageSizeZero: true
  params: count=countSql
  reasonable: false
  support-methods-arguments: true
  1. ここでは主に mybatis-plus の構成について説明します。実際、ハンプ ルール、エンティティ クラス パス、および XML パスを有効にするなど、以前の mybatis 構成と非常に似ており、これらはすべて以前と同じです。
  2. log-impl の設定ですが、実際には mp の実行 SQL を出力します。個人的には、初めて使用するときは有効にすることをお勧めします。使い慣れてきたら、この行をコメントしたり削除したりすると、ログが少なくなるため、今後はログを通じて問題を確認できます。
  3. global-config 設定に注目してみましょう。ここで設定されているのは、グローバル トゥームストーン delFlag、つまり擬似削除です。自動クエリ中に、mp は削除されたデータを除外するために where ステートメントの後に del_flag = 0 を自動的に追加します。また、更新および削除時にこの条件も自動的に追加します。
    ただし、SQL ステートメントを手動で作成する場合は、手動で追加する必要があります。この関数の設定については、状況によって異なります。結局、一度設定すると、より必須になる可能性があるため、このグローバル tombstone フィールドを設定する必要はありません。条件 del_flag = 0 を手動で追加できます。つまり、実際の状況に応じて柔軟に使用できます。

4.MPアプリケーション

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

@MapperScan("com.taoge.mapper") // 扫描mapper接口包
@SpringBootApplication
public class MPApplication {
    
    

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

5. ハンドラーパッケージの下にオートフィラーを作成します

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

import java.time.LocalDateTime;

/**
 * MyBatis-Plus自定义填充处理器
 */
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    

    // 默认策略:如果属性有值则不覆盖,如果填充值为null则不填充

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

    /**
     * 做insert插入时自动填充的值(这里一般是create_time和update_time)
     */
    @Override
    public void insertFill(MetaObject metaObject) {
    
    
        if (metaObject.hasGetter(CREATE_TIME) && metaObject.hasGetter(UPDATE_TIME)) {
    
     // 实体类有get方法,就是有这个字段
            LocalDateTime localDateTime = LocalDateTime.now();
            this.strictInsertFill(metaObject, CREATE_TIME, () -> localDateTime, LocalDateTime.class); // 起始版本 3.3.3(推荐)
            this.strictInsertFill(metaObject, UPDATE_TIME, () -> localDateTime, LocalDateTime.class); // 起始版本 3.3.3(推荐)
        }
    }

    /**
     * 做update更新时自动填充的值(更新就只针对update_time)
     */
    @Override
    public void updateFill(MetaObject metaObject) {
    
    
        if (metaObject.hasGetter(UPDATE_TIME)) {
    
    
            metaObject.setValue(UPDATE_TIME, LocalDateTime.now());
            // this.strictUpdateFill(metaObject, UPDATE_TIME, () -> LocalDateTime.now(), LocalDateTime.class);
        }
    }
}
  1. テーブルの create_time フィールドと update_time フィールドが新規または更新時に自動的に入力され、手動で設定する必要がないことを期待しているため、上記の自動入力機能が構成されています。
  2. ここで説明するフィラーは、実際には、createBy、updateBy、つまり作成者と更新者を追加するなど、より充実したものにすることができます。これらは実際の状況に応じて追加できますが、一般的には上記の 2 つ (作成時間、更新時間) で十分です。
  3. ここでの時間型は Date 型ではなく、jdk8 の LocalDateTime 型を使用します。プロジェクト内の時間型はすべて LocalDateTime を使用します (LocalDateTime を推奨)
  4. 実は、公式の更新オートフィラー コードには小さな問題があります。最初にクエリを実行してから更新すると、updateTime 値が更新されないことがわかります。これは、デフォルトのポリシーの問題が原因です。値がある場合は更新されません。上書きされるため、直接metaObject.setValue()を実行し、次の行をコメントアウトします。これにより、このバグが回避されます

6. エンティティクラスの作成
(1) po パッケージ配下に新しいベースパッケージを作成し、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 implements Serializable {
    
    

    private static final long serialVersionUID = -922201555125882232L;

    /** 创建时间 */
    @TableField(fill = FieldFill.INSERT) // 插入自动填充
    private LocalDateTime createTime;

    /** 更新时间 */
    @TableField(fill = FieldFill.INSERT_UPDATE) // 插入或更新时自动填充
    private LocalDateTime updateTime;

    /** 删除标记(0未删除,1已删除) */
//    @TableLogic // 此注解表示该字段是逻辑删除字段(这里注掉是因为现用的mp版本是3.4.2,从3.3.0版本后就可以省略该注解)
    private Integer delFlag;
}
  1. オートフィラーは上で構成されているため、ここで使用する場合は、対応するアノテーションをフィールドに追加する必要があります。これにより、挿入および更新時に値を手動で設定する必要がなくなります。
  2. 注: 上記で構成された更新オートフィラーは、特殊な場合、つまり、一部のフィールドをカスタマイズして更新する場合にも失敗します (カスタム更新フィールドなど: 名前 = Zhang San の携帯電話番号を xxxx に変更する)。この小さなバグはまだ公式によって直接修正されていませんが、後で紹介する別の方法で解決できます。

(2) po パッケージの下に新しい Student クラスを作成し、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;

/**
 * 学生po
 */
@Data
@TableName(value = "t_student") // 指定数据库里对应的表名
public class Student extends BaseEntity {
    
    

    private static final long serialVersionUID = 3819669465179936254L;

    // @TableId(type = IdType.AUTO):表主键id注解,AUTO表示id是自增的
    // @TableField(value = "major_id"):表字段注解,value表示对应表里的字段,但只要表字段命名规范,实体类里驼峰命名,就可不加此注解

    /** 学生id */
//    @TableId(type = IdType.AUTO) // 如果你的表主键id是自增的,就加上这行注解,我这里的id是非自增,所以不用加@TableId注解
    private Long id;

    /** 姓名 */
    private String name;

    /** 性别:1男,2女,0未知 */
    private Integer gender;

    /** 专业id */
//    @TableField(value = "major_id") // 指定对应表里字段,为了方便,此注解可以不加
    private Integer majorId;

    /** 手机号 */
    private String phone;

    //======下面是我额外加的字段=========

    /** 所属专业名称 */
    @TableField(exist = false) // 非表字段(这种就得加上@TableField注解,exist默认为true,为false时表示非数据表字段)
    private String majorName; // 这个字段在mybatis-plus自动查询的时候就不会带上,不过当你在xml里自定义写多表查询sql时可映射此字段
}

7. マッパーインターフェイスの作成: StudentMapper

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

public interface StudentMapper extends BaseMapper<Student> {
    
    
}
  1. マッパーインターフェイスはmpのBaseMapperインターフェイスを直接継承し、対応するエンティティクラスがStudentであることを指定します。
  2. マッパー パッケージ全体をスキャンするために @MapperScan アノテーションがスタートアップ クラスに追加されているため、マッパー インターフェイスに @Mapper や @Repository などのアノテーションを追加する必要はありません。

8. サービスインターフェースと実装クラスの作成
(1) StudentServiceインターフェース

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

import java.util.List;

public interface StudentService extends IService<Student> {
    
    
}

サービス インターフェイスは mp の IService インターフェイスを直接継承し、エンティティ クラスを Student として指定するため、IService に付属するメソッドを使用できます。

(2) 実装クラス

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 {
    
    
}

ここでは ServiceImpl を継承し、対応するマッパーとクラスを指定して、自動カード操作が完了するようにします。

3: テスト コントローラーを作成する

1. 新しいインターフェース

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注解:可代替@Autowired,但是必须加上final(其实就是通过构造器来注入)
public class StudentController {
    
    

    // 为了演示,我这里把service和mapper都注入了进来,实际开发只需注入一个service,主要是介绍service的mapper对的操作区别
    // 其实service和mapper在功能上基本上是一样的,service有的功能mapper也有,只是他两用的时候在方法名字上有区别
    // service里的方法内部再去调用了mapper,可以点进去看下源码就明白了
    // 实际中,可以在service中自定义一些方法,在serviceImpl中再调用mapper,当明白了mybatisplus的使用后可自由发挥

    private final StudentService studentService;
    private final StudentMapper studentMapper;

    /**
     * 新增
     */
    @PostMapping("/add")
    public Result add() {
    
    
        // service演示新增
        Student student = new Student();
        student.setName("张三");
        student.setGender(1);
        student.setMajorId(1);
        student.setPhone("18300001111");
        boolean save = studentService.save(student);
        // mapper演示新增
        Student student1 = new Student();
        student1.setName("小芳");
        student1.setGender(2);
        student1.setMajorId(1);
        student1.setPhone("18300002222");
        int insert = studentMapper.insert(student1); // 上面的save内部也是调用insert,只是使用时名称不一样
        log.info("【add】save={}, insert={}", save, insert);
        // 批量插入
        Student student2 = new Student();
        student2.setName("小三");
        student2.setGender(2);
        student2.setMajorId(2);
        student2.setPhone("18300003333");
        Student student3 = new Student();
        student3.setName("小明");
        student3.setGender(1);
        student3.setMajorId(1);
        student3.setPhone("18300004444");
        List<Student> studentList = new ArrayList<>();
        studentList.add(student2);
        studentList.add(student3);
        studentService.saveBatch(studentList); // saveBatch,只能用service去调用
        return Result.success(save && insert == 1);
    }
}

Student テーブルの主キー ID はインクリメントされていないため、ここでは setId を持っていませんが、mybatis-plus は自動的に長い ID を生成します。もちろん、プロジェクトで ID 生成戦略を使用して、それを生成し、雪の結晶などの ID を手動で設定します。アルゴリズムによって ID が生成されます。これはより良いものになります。

postman を使用して http://localhost:8080/student/add をリクエストします。デバッグ プロセスは次のとおりです。
デバッグを追加
テーブルデータ
2. クエリ インターフェイス

   /**
     * 查询
     */
    @GetMapping("/query/{id}")
    public Result query(@PathVariable("id") Long id) {
    
    
        // 1. 根据id查询
        Student student = studentService.getById(id);
//        student = studentMapper.selectById(id); // 等同于上面一行
        log.info("【query】student={}", JSON.toJSONString(student));

        // 2. 查询所有(查询列表时可以加上pagehelper分页,这里就不演示了,自己尝试,很简单)
        List<Student> studentAllList = studentService.list(); // 或者写成.list(null),两个是一样的
//        List<Student> studentAllList = studentMapper.selectList(null); // 等价于上面的写法
        log.info("【query】studentAllList={}", JSON.toJSONString(studentAllList));

        // 3. 查询器查询

        // 条件构造器(不建议用这个):查询name=张三
        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", "张三"); // 条件查询(eq是等于,即name='张三')
        queryWrapper.select("id", "name", "major_id"); // 查询指定字段(不加这行会默认查询所有字段,注意:这里的字段填的是表里的字段)
        Student student1 = studentService.getOne(queryWrapper); // getOne:表示只去查询一条结果
//        Student student1 = studentMapper.selectOne(queryWrapper); 等同于上面一行
        log.info("【query】student1={}", JSON.toJSONString(student1)); // 注意:由于我上面加了指定字段查询,所以这里只有查的这几个字段才有值

        // lambda查询构造器(推荐):查询major_id=1的学生列表
        LambdaQueryWrapper<Student> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Student::getMajorId, 1); // 条件:where major_id = 1(如果多条件查询可以继续.eq这样添加)
        lambdaQueryWrapper.select(Student::getId, Student::getName, Student::getGender); // 我只想查这三个字段
        lambdaQueryWrapper.orderByDesc(Student::getCreateTime); // 排序:order by create_time desc
        List<Student> studentList = studentService.list(lambdaQueryWrapper);
        log.info("【query】studentList={}", JSON.toJSONString(studentList));

        // 这里再写一个service里我们自定义的方法:查询专业为1且性别为女
        List<Student> studentList2 = studentService.getByMajorIdAndGender(1, 2);
        log.info("【query】studentList2={}", JSON.toJSONString(studentList2));
        return Result.success(true);
    }

StudentServiceImpl: 次のメソッドを追加します

    // 这里可以注入mapper进来进行操作,也可以用mp的baseMapper进行操作(因为mapper继承了baseMapper)
    // 如果你有复杂的sql或者自定义的sql,那么就按照原生的mybatis那样操作,去mapper里写接口,xml里写sql
    private final StudentMapper studentMapper;

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

        // 由于StudentService继承了IService,所以这里可以直接用service里的方法,也可以用mapper
        // 用service操作
        List<Student> serviceList = this.list(queryWrapper); // 这里实现类里可直接使用IService里的方法
        // 用mapper操作
        List<Student> mapperList = baseMapper.selectList(queryWrapper); // 这里也可以用:studentMapper.selectList(queryWrapper)
        log.info("【getByMajorIdAndGender】serviceList={}", serviceList);
        log.info("【getByMajorIdAndGender】mapperList={}", mapperList); // 两条查询肯定是一样的
        return mapperList;
    }

上記のサービスで実行できることは、マッパーでも実行できます。サービスのマッパーは引き続きマッパーを使用してクエリを実行するため、自分で試すことができます。さらに、ファジーなど、より一般的に使用される特別なクエリもあります。最後に紹介するクエリ

postman リクエストを使用します: http://localhost:8080/student/query/1472863272568754178
IDクエリ
3. インターフェイスを更新します。

   /**
     * 更新
     */
    @PostMapping("/update/{id}")
    public Result update(@PathVariable("id") Long id) {
    
    
        // 1. 根据id更新
        Student student = new Student();
        student.setId(id);
        student.setName("张三三"); // 根据id更新姓名为张三三
        boolean updateById = studentService.updateById(student); // 会自动填充updateTime
        log.info("【update】updateById={}", updateById);

        // 2. 指定条件更新:把姓名=张三三的专业改为3
        LambdaUpdateWrapper<Student> updateWrapper = new LambdaUpdateWrapper<>(); // 创建lambda更新器
        updateWrapper.set(Student::getMajorId, 3); // 更新器中set是要更新的字段,是最后结果
        updateWrapper.set(Student::getUpdateTime, DateUtil.toLocalDateTime(new Date())); // 这里需手动setUpdateTime,因为这里更新的字段值是我们自定义的,我们自定义了updateWrapper.set()
        updateWrapper.eq(Student::getName, "张三三"); // 而eq是更新条件,即sql是:set major_id = 3 where name = '张三三'
        boolean update = studentService.update(updateWrapper);
        log.info("【update】update={}", update);

        // 这里提一点,如果我要吧表中的某一个字段由原先的非null改为null,那么就不能用updateById,不会生效
        // 建议用指定字段更新来实现,当然也可以用原生的手动写sql语句实现
        // 比如上面的,我现在要把姓名=张三三的专业改为null,则改为updateWrapper.set(Student::getMajorId, null)
        return Result.success(updateById && update);
    }

注: 指定された条件が更新されると、この更新は弊社によってカスタマイズされているため、updateTime の自動入力は無効になり、mp は入力されないため、setUpdateTime は手動で追加されます

postman リクエスト: http://localhost:8080/student/update/1472863272568754178
IDの更新
状態の更新
4. インターフェイスを削除します。

   /**
     * 删除
     */
    @PostMapping("/delete/{id}")
    public Result delete(@PathVariable("id") Long id) {
    
    
        // 一般删除前可以先查一下,不为空再删除
        Student student = studentService.getById(id);
        if (null == student) {
    
    
            return Result.error(CodeMsg.DELETE_FAIL);
        }

        // 说明:removeById表示根据id删除(常用),还有根据id批量删除,方法是removeByIds
        // 但如果yml里配的是伪删除,那么removeById由原本的执行delete变成走update,即把del_flag字段值改为1

        // 注意:由于现yml里配置了伪删除,如果走mp的删除接口,则会有个小bug:数据虽删了但update_time没有自动填充改变,还是原来的时间
        // 为避免这个bug,既然是伪删,我建议还是全走update,手动更新del_flag和update_time这两个字段,或者手动在xml里写sql实现

        // 1. 根据id删除(走根据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. 条件删除:删除专业=5的女学生(同样,伪删除走指定条件更新)
        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); // 由于没有专业id=5的数据,所以返回false
        log.info("【delete】update1={}", update1);

//        // 如果你的表没有类似的del_flag字段,直接是真删,则删除为下面2种:
//        // 根据id删除
//        studentService.removeById(id); // 或者studentMapper.deleteById(id)
//        // 根据条件删除
//        LambdaQueryWrapper<Student> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(Student::getMajorId, 5);
//        queryWrapper.eq(Student::getGender, 2);
//        studentService.remove(queryWrapper);
        return Result.success(update, "删除成功");
    }

Postman アクセス: http://localhost:8080/student/delete/1472863272568754178
IDの誤った削除
5. 特別なクエリの概要
まず、簡単にテストできるように、削除された Zhang Sansan の delFlag を 0 に変更します。

   /**
     * 特殊查询介绍(这里我就都用service、lambda查询器来演示)
     */
    @GetMapping("/query2")
    public Result query2() {
    
    
        // 1. 模糊查询:姓名中有三的学生
        LambdaQueryWrapper<Student> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(Student::getName, "三"); // name like '%三%'(对应还有个不常用的notLike)
//        queryWrapper.likeLeft(Student::getName, "三"); // name like '%三'
//        queryWrapper.likeRight(Student::getName, "三"); // name like '三%'
        queryWrapper.orderByDesc(Student::getCreateTime); // 倒序输出
        List<Student> likeList = studentService.list(queryWrapper);
        log.info("【query2】likeList={}", JSON.toJSONString(likeList));

        // 2. 范围查询:大于小于
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.gt(Student::getCreateTime, "2021.12.20 17:38:00"); // gt是大于的意思:create_time > 2021.12.17 06:00:00
        queryWrapper.lt(Student::getCreateTime, "2021.12.25 22:00:00"); // lt是小于的意思:create_time < 2021.12.18 22:00:00
        List<Student> gltList = studentService.list(queryWrapper);
        // 还有:ge(大于等于>=)、le(小于等于<=)、ne(不等于<>)、between(两值之间),照葫芦画瓢就行,不演示了
        log.info("【query2】gltList={}", JSON.toJSONString(gltList));

        // 3. 分组查询:groupBy
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.groupBy(Student::getMajorId);
        List<Student> groupList = studentService.list(queryWrapper);
        log.info("【query2】groupList={}", JSON.toJSONString(groupList));

        // 4. in查询
        queryWrapper = new LambdaQueryWrapper<>();
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        queryWrapper.in(Student::getName, list); // 对应的还有notIn
        List<Student> inList = studentService.list(queryWrapper);
        log.info("【query2】inList={}", JSON.toJSONString(inList));

        // 5. 空查询(不常用)
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNull(Student::getName); // name is null,对应的肯定还有isNotNull
        List<Student> nullList = studentService.list(queryWrapper);
        log.info("【query2】nullList={}", JSON.toJSONString(nullList));

        // 6. 动态查询
        // 上面的不管是eq,还是gt、in等,其实在执行时最前面还有个布尔参数,不传的话默认都是true
        // 像上面的所有查询,我们都没传这个参数,其实内部自动为我们设置成了true,点进去看源码就知道了
        // 这个布尔参数的意思:为true表示带上这个条件,为false则忽略此条件,其实就是做动态SQL用
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(false, Student::getName, "张三"); // 这里设成false,则此设置不生效,等于没有这行,依然会查询所有的学生
        queryWrapper.eq(nullList.size() > 0, Student::getMajorId, 1); // 如果nullList有数据此设置才生效,才会查询专业=1的学生
        List<Student> dynamicList = studentService.list(queryWrapper);
        log.info("【query2】dynamicList={}", JSON.toJSONString(dynamicList));
        return Result.success(true);
    }


ファジークエリ
範囲クエリ
グループクエリ
動的クエリ
postman アクセス: 上記の http://localhost:8080/student/query2、これは mybatis-plus の最も一般的に使用されるチュートリアルです。すべてのコードは実際のテストに合格しています。問題はありません。注意すべき点が 1 つあります各テーブルには del_flag フィールドがあるため、yml ファイルでグローバル トゥームストーンを設定する必要はありませんが、手動で実装します。たとえば、クエリを実行するときに条件を手動で追加します: delFlag = 0,削除する場合と同様ですので、慣れてから柔軟に使ってください(参考になったら「いいね!」をお願いします)。

MyBatis-Plus の公式 Web サイトを添付します: https://baomidou.com/ (ドキュメントが表示されます)

おすすめ

転載: blog.csdn.net/qq_36737803/article/details/122036386
おすすめ