玄子Share - mybatis-Plus 3.5.3.1 学习笔记

news2024/11/25 20:43:18

玄子Share - mybatis-Plus 3.5.3.1 学习笔记

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NN01yt9J-1688535341267)(./assets/relationship-with-mybatis.png)]

介绍

MyBatis-Plus (opens new window)(简称 MP)是一个 [MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

愿景:我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

前期准备

使用场景

环境版本
Java17
IDEA2023.1
Maven3.9.1
SpringBoot3.1.1
mybatis-Plus3.5.3.1

Maven依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>
    </dependencies>

数据表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e6TDZ3BU-1688535341268)(./assets/image-20230704115437447.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OpdAhQZl-1688535341268)(./assets/image-20230704115504263.png)]

/*
 Navicat Premium Data Transfer

 Source Server         : XuanZi
 Source Server Type    : MySQL
 Source Server Version : 50740 (5.7.40)
 Source Host           : localhost:3306
 Source Schema         : user

 Target Server Type    : MySQL
 Target Server Version : 50740 (5.7.40)
 File Encoding         : 65001

 Date: 04/07/2023 11:55:20
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',
  `age` int(11) NULL DEFAULT NULL COMMENT '年龄',
  `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',
  `deleted` int(11) NULL DEFAULT 0 COMMENT '逻辑删除默认0',
  `updateTime` datetime NULL DEFAULT NULL COMMENT '修改时间',
  `insertTime` datetime NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'Jone', 18, 'test1@baomidou.com', 0, '2023-07-04 11:53:46', '2023-07-04 11:53:46');
INSERT INTO `user` VALUES (2, 'Jack', 20, 'test2@baomidou.com', 0, '2023-07-04 11:53:46', '2023-07-04 11:53:46');
INSERT INTO `user` VALUES (3, 'Tom', 28, 'test3@baomidou.com', 0, '2023-07-04 11:53:46', '2023-07-04 11:53:46');
INSERT INTO `user` VALUES (4, 'Sandy', 21, 'test4@baomidou.com', 0, '2023-07-04 11:53:46', '2023-07-04 11:53:46');
INSERT INTO `user` VALUES (5, 'Billie', 24, 'test5@baomidou.com', 0, '2023-07-04 11:53:46', '2023-07-04 11:53:46');

SET FOREIGN_KEY_CHECKS = 1;

快速上手

指定数据源

在 application.yml 配置文件中编写

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/user?useUnicode=TRUE&characterEncoding=UTF-8&serverTimezone=GMT-8

驼峰转换

mybatis-plus,默认开启了下滑线-驼峰转换,会把实体类字段(驼峰命名)自动转换为下划线命名,后到数据库匹配字段,就会导致 sql 异常

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false

关闭驼峰转转换

创建 User 实体类对象

package com.xuanzi.mybatisplus.etity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String email;
    private int deleted;
    private Date updateTime;
    private Date insertTime;
}

使用 lombok 完成 Getter 和 Setter 方法及构造器

创建 UserMapper 接口

继承 BaseMapper 工具类,并指定泛型,即为数据表对应的实体类对象BaseMapper<User>

package com.xuanzi.mybatisplus.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xuanzi.mybatisplus.etity.User;
import org.apache.ibatis.annotations.Mapper;

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

@Mapper():目的就是为了不再写 mapper 映射文件,是注解开发时用的。

或者在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹

@MapperScan(“com.xuanzi.mybatisplus.mapper”)

运行代码

package com.xuanzi.mybatisplus;

import com.xuanzi.mybatisplus.etity.User;
import com.xuanzi.mybatisplus.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.jupiter.api.Test;

import java.util.List;

@SpringBootTest
class Test2 {
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        List<User> patients = userMapper.selectList(null);
        patients.forEach(System.out::println);
    }
}

UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h2UVlhJj-1688535341268)(./assets/image-20230704121417053.png)]

基础 CRUD

新增

    @Test
    void insert() {
        int result = userMapper.insert(new User("张三", 18, "123@.com"));
        System.out.println(result);
        contextLoads();
    }

修改

    @Test
    void update() {
        User user = new User();
        user.setId(5);
        user.setName("玄子");
        user.setAge(13);
        userMapper.updateById(user);
        contextLoads();
    }

通过 id 修改传递 user 对象

删除

    @Test
    void deleteById() {
        int i = userMapper.deleteById(2);
        System.out.println(i);
        contextLoads();
    }

    @Test
    void deleteBatchIds() {
        int i = userMapper.deleteBatchIds(Arrays.asList(1, 4));
        System.out.println(i);
        contextLoads();
    }

    @Test
    void deleteByMap() {
        Map<String, Object> map = new HashMap<>();
        map.put("name", "Jone");
        map.put("age", 18);
        int i = userMapper.deleteByMap(map);
        System.out.println(i);
        contextLoads();
    }

依次为:

  • 通过 ID 删除
  • 批量删除,传递 ID 集合
  • 条件删除,传递 Map 对应 set key = val

查询

    @Test
    void selectByid() {
        User result = userMapper.selectById(7);
        System.out.println(result);
    }

    @Test

    void selectBatchIds() {
        List<User> result = userMapper.selectBatchIds(Arrays.asList(1, 2, 4, 9));
        result.forEach(System.out::println);
    }

    @Test
    void selectByMap() {
        Map<String, Object> map = new HashMap<>();
        map.put("name", "Jone");
        map.put("age", 18);
        List<User> result = userMapper.selectByMap(map);
        result.forEach(System.out::println);
    }

依次为:

  • 通过 ID 查询
  • 批量查询,传递 ID 集合
  • 条件查询,传递 Map 对应 where key = val

主键策略

@TableId(type = IdType.AUTO)
    private int id;

主键自增长,数据库字段也要设置自增长,否则报错

public enum IdType {
    AUTO(0),
    NONE(1),
    INPUT(2),
    ASSIGN_ID(3),
    ASSIGN_UUID(4);

    private final int key;

    private IdType(int key) {
        this.key = key;
    }

    public int getKey() {
        return this.key;
    }
}
  • AUTO:主键自增长
  • NONE:无策略
  • INPUT:用户输入ID
  • ASSIGN_ID:雪花算法
  • ASSIGN_UUID:全局唯一
  • 默认使用雪花算法+UUID(不含中划线)

逻辑删除

只对自动注入的 sql 起效,删除: 转变为 更新

配置 yml

在 application.yml 配置文件中编写

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

@TableLogic注解

 @TableLogic
    private int deleted;

实体类字段上加上@TableLogic注解

分页查

    @Test
    void pageSelect() {
        Page<User> page = new Page<>(1, 5);
        userMapper.selectPage(page, null);
        page.getRecords().forEach(System.out::println);
        System.out.println("===============");
        System.out.println(page.getTotal());
    }

page 对象的两个参数和 sql 的 limit 用法一致

Page

该类继承了 IPage 类,实现了 简单分页模型 如果你要实现自己的分页模型可以继承 Page 类或者实现 IPage

属性名类型默认值描述
recordsListemptyList查询数据列表
totalLong0查询列表总记录数
sizeLong10每页显示条数,默认 10
currentLong1当前页
ordersListemptyList排序字段信息,允许前端传入的时候,注意 SQL 注入问题,可以使用 SqlInjectionUtils.check(...) 检查文本
optimizeCountSqlbooleantrue自动优化 COUNT SQL 如果遇到 jSqlParser 无法解析情况,设置该参数为 false
optimizeJoinOfCountSqlbooleantrue自动优化 COUNT SQL 是否把 join 查询部分移除
searchCountbooleantrue是否进行 count 查询,如果指向查询到列表不要查询总记录数,设置该参数为 false
maxLimitLong单页分页条数限制
countIdStringxml 自定义 count 查询的 statementId 也可以不用指定在分页 statementId 后面加上 _mpCount 例如分页 selectPageById 指定 count 的查询 statementId 设置为 selectPageById_mpCount 即可默认找到该 SQL 执行

自动填充功能

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    @TableField(fill = FieldFill.INSERT)
    private Date insertTime;
public enum FieldFill {
    DEFAULT,
    INSERT,
    UPDATE,
    INSERT_UPDATE;

    private FieldFill() {
    }
}
  • DEFAULT:默认不生效
  • INSERT:插入生效
  • UPDATE:修改生效
  • INSERT_UPDATE:插入修改均生效

重写方法

实现 implements MetaObjectHandler 方法

package com.xuanzi.mybatisplus.handler;

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.util.Date;

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insertFill");
        this.setFieldValByName("insertTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start updateFill");
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

指定 FieldName 插入类型 以及 元对象

条件构造器

  • 以下出现的第一个入参boolean condition表示该条件是否加入最后生成的sql中,例如:query.like(StringUtils.isNotBlank(name), Entity::getName, name) .eq(age!=null && age >= 0, Entity::getAge, age)
  • 以下代码块内的多个方法均为从上往下补全个别boolean类型的入参,默认为true
  • 以下出现的泛型Param均为Wrapper的子类实例(均具有AbstractWrapper的所有方法)
  • 以下方法在入参中出现的R为泛型,在普通wrapper中是String,在LambdaWrapper中是函数(例:Entity::getId,Entity为实体类,getId为字段idgetter Method)
  • 以下方法入参中的R column均表示数据库字段,当R具体类型为String时则为数据库字段名(字段名是数据库关键字的自己用转义符包裹!)!而不是实体类数据字段名!!!,另当R具体类型为SFunction时项目runtime不支持eclipse自家的编译器!!!
  • 以下举例均为使用普通wrapper,入参为MapList的均以json形式表现!
  • 使用中如果入参的Map或者List,则不会加入最后生成的sql中!!!
  • 有任何疑问就点开源码看

不支持以及不赞成在 RPC 调用中把 Wrapper 进行传输

  1. wrapper 很重
  2. 传输 wrapper 可以类比为你的 controller 用 map 接收值(开发一时爽,维护火葬场)
  3. 正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作
  4. 我们拒绝接受任何关于 RPC 传输 Wrapper 报错相关的 issue 甚至 pr

AbstractWrapper

QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为

allEq

allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
  • 全部eq(或个别 isNull)

params : key为数据库字段名,value为字段值
null2IsNull : 为true则在mapvaluenull时调用 isNull 方法,为false时则忽略valuenull

  • 例1: allEq({id:1,name:"老王",age:null})—>id = 1 and name = '老王' and age is null
  • 例2: allEq({id:1,name:"老王",age:null}, false)—>id = 1 and name = '老王'
allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) =

filter : 过滤函数,是否允许字段传入比对条件中

paramsnull2IsNull : 同上

  • 例1: allEq((k,v) -> k.contains("a"), {id:1,name:"老王",age:null})—>name = '老王' and age is null
  • 例2: allEq((k,v) -> k.contains("a"), {id:1,name:"老王",age:null}, false)—>name = '老王'

eq

eq(R column, Object val)
eq(boolean condition, R column, Object val)
  • 等于 =
  • 例: eq("name", "老王")—>name = '老王'

ne

ne(R column, Object val)
ne(boolean condition, R column, Object val)
  • 不等于 <>
  • 例: ne("name", "老王")—>name <> '老王'

gt

gt(R column, Object val)
gt(boolean condition, R column, Object val)
  • 大于 >
  • 例: gt("age", 18)—>age > 18

ge

ge(R column, Object val)
ge(boolean condition, R column, Object val)
  • 大于等于 >=
  • 例: ge("age", 18)—>age >= 18

lt

lt(R column, Object val)
lt(boolean condition, R column, Object val)
  • 小于 <
  • 例: lt("age", 18)—>age < 18

le

le(R column, Object val)
le(boolean condition, R column, Object val)
  • 小于等于 <=
  • 例: le("age", 18)—>age <= 18

between

between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)
  • BETWEEN 值1 AND 值2
  • 例: between("age", 18, 30)—>age between 18 and 30

notBetween

notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
  • NOT BETWEEN 值1 AND 值2
  • 例: notBetween("age", 18, 30)—>age not between 18 and 30

like

like(R column, Object val)
like(boolean condition, R column, Object val)
  • LIKE ‘%值%’
  • 例: like("name", "王")—>name like '%王%'

notLike

notLike(R column, Object val)
notLike(boolean condition, R column, Object val)
  • NOT LIKE ‘%值%’
  • 例: notLike("name", "王")—>name not like '%王%'

likeLeft

likeLeft(R column, Object val)
likeLeft(boolean condition, R column, Object val)
  • LIKE ‘%值’
  • 例: likeLeft("name", "王")—>name like '%王'

likeRight

likeRight(R column, Object val)
likeRight(boolean condition, R column, Object val)
  • LIKE ‘值%’
  • 例: likeRight("name", "王")—>name like '王%'

notLikeLeft

notLikeLeft(R column, Object val)
notLikeLeft(boolean condition, R column, Object val)
  • NOT LIKE ‘%值’
  • 例: notLikeLeft("name", "王")—>name not like '%王'

notLikeRight

notLikeRight(R column, Object val)
notLikeRight(boolean condition, R column, Object val)
  • NOT LIKE ‘值%’
  • 例: notLikeRight("name", "王")—>name not like '王%'

isNull

isNull(R column)
isNull(boolean condition, R column)
  • 字段 IS NULL
  • 例: isNull("name")—>name is null

isNotNull

isNotNull(R column)
isNotNull(boolean condition, R column)
  • 字段 IS NOT NULL
  • 例: isNotNull("name")—>name is not null

in

in(R column, Collection<?> value)
in(boolean condition, R column, Collection<?> value)
  • 字段 IN (value.get(0), value.get(1), …)
  • 例: in("age",{1,2,3})—>age in (1,2,3)
in(R column, Object... values)
in(boolean condition, R column, Object... values)
  • 字段 IN (v0, v1, …)
  • 例: in("age", 1, 2, 3)—>age in (1,2,3)

notIn

notIn(R column, Collection<?> value)
notIn(boolean condition, R column, Collection<?> value)
  • 字段 NOT IN (value.get(0), value.get(1), …)
  • 例: notIn("age",{1,2,3})—>age not in (1,2,3)
notIn(R column, Object... values)
notIn(boolean condition, R column, Object... values)
  • 字段 NOT IN (v0, v1, …)
  • 例: notIn("age", 1, 2, 3)—>age not in (1,2,3)

inSql

inSql(R column, String inValue)
inSql(boolean condition, R column, String inValue)
  • 字段 IN ( sql语句 )
  • 例: inSql("age", "1,2,3,4,5,6")—>age in (1,2,3,4,5,6)
  • 例: inSql("id", "select id from table where id < 3")—>id in (select id from table where id < 3)

notInSql

notInSql(R column, String inValue)
notInSql(boolean condition, R column, String inValue)
  • 字段 NOT IN ( sql语句 )
  • 例: notInSql("age", "1,2,3,4,5,6")—>age not in (1,2,3,4,5,6)
  • 例: notInSql("id", "select id from table where id < 3")—>id not in (select id from table where id < 3)

groupBy

groupBy(R... columns)
groupBy(boolean condition, R... columns)
  • 分组:GROUP BY 字段, …
  • 例: groupBy("id", "name")—>group by id,name

orderByAsc

orderByAsc(R... columns)
orderByAsc(boolean condition, R... columns)
  • 排序:ORDER BY 字段, … ASC
  • 例: orderByAsc("id", "name")—>order by id ASC,name ASC

orderByDesc

orderByDesc(R... columns)
orderByDesc(boolean condition, R... columns)
  • 排序:ORDER BY 字段, … DESC
  • 例: orderByDesc("id", "name")—>order by id DESC,name DESC

orderBy

orderBy(boolean condition, boolean isAsc, R... columns)
  • 排序:ORDER BY 字段, …
  • 例: orderBy(true, true, "id", "name")—>order by id ASC,name ASC

having

having(String sqlHaving, Object... params)
having(boolean condition, String sqlHaving, Object... params)
  • HAVING ( sql语句 )
  • 例: having("sum(age) > 10")—>having sum(age) > 10
  • 例: having("sum(age) > {0}", 11)—>having sum(age) > 11

func

func(Consumer<Children> consumer)
func(boolean condition, Consumer<Children> consumer)
  • func 方法(主要方便在出现if…else下调用不同方法能不断链)
  • 例: func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})

or

or()
or(boolean condition)
  • 拼接 OR

    注意事项:

    主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)

  • 例: eq("id",1).or().eq("name","老王")—>id = 1 or name = '老王'

or(Consumer<Param> consumer)
or(boolean condition, Consumer<Param> consumer)
  • OR 嵌套
  • 例: or(i -> i.eq("name", "李白").ne("status", "活着"))—>or (name = '李白' and status <> '活着')

and

and(Consumer<Param> consumer)
and(boolean condition, Consumer<Param> consumer)
  • AND 嵌套
  • 例: and(i -> i.eq("name", "李白").ne("status", "活着"))—>and (name = '李白' and status <> '活着')

nested

nested(Consumer<Param> consumer)
nested(boolean condition, Consumer<Param> consumer)
  • 正常嵌套 不带 AND 或者 OR
  • 例: nested(i -> i.eq("name", "李白").ne("status", "活着"))—>(name = '李白' and status <> '活着')

apply

apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)
  • 拼接 sql

    注意事项:

    该方法可用于数据库函数 动态入参的params对应前面applySql内部的{index}部分.这样是不会有sql注入风险的,反之会有!

  • 例: apply("id = 1")—>id = 1

  • 例: apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")—>date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

  • 例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08")—>date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

last

last(String lastSql)
last(boolean condition, String lastSql)
  • 无视优化规则直接拼接到 sql 的最后

    注意事项:

    只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用

  • 例: last("limit 1")

exists

exists(String existsSql)
exists(boolean condition, String existsSql)
  • 拼接 EXISTS ( sql语句 )
  • 例: exists("select id from table where age = 1")—>exists (select id from table where age = 1)

notExists

notExists(String notExistsSql)
notExists(boolean condition, String notExistsSql)
  • 拼接 NOT EXISTS ( sql语句 )
  • 例: notExists("select id from table where age = 1")—>not exists (select id from table where age = 1)

QueryWrapper

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取

select

select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
  • 设置查询字段

以上方法分为两类.第二类方法为:过滤查询字段(主键除外),入参不包含 class 的调用前需要wrapper内的entity属性有值! 这两类方法重复调用以最后一次为准

  • 例: select("id", "name", "age")
  • 例: select(i -> i.getProperty().startsWith("test"))

UpdateWrapper

说明:

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件
LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!

set

set(String column, Object val)
set(boolean condition, String column, Object val)
  • SQL SET 字段
  • 例: set("name", "老李头")
  • 例: set("name", "")—>数据库字段值变为空字符串
  • 例: set("name", null)—>数据库字段值变为null

setSql

setSql(String sql)
  • 设置 SET 部分 SQL
  • 例: setSql("name = '老李头'")

lambda

  • 获取 LambdaWrapper
    QueryWrapper中是获取LambdaQueryWrapper
    UpdateWrapper中是获取LambdaUpdateWrapper

使用 Wrapper 自定义SQL

注意事项:

需要mybatis-plus版本 >= 3.0.7 param 参数名要么叫ew,要么加上注解@Param(Constants.WRAPPER) 使用${ew.customSqlSegment} 不支持 Wrapper 内的entity生成where语句

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/724808.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker 镜像的使用与创建(三)

相关文章&#xff1a; linux上docker容器运行web应用简单介绍(二&#xff09;_做测试的喵酱的博客-CSDN博客 linux docker安装及报错处理_做测试的喵酱的博客-CSDN博客 Docker 容器使用 | 菜鸟教程 linux应用docker基本使用&#xff08;一&#xff09;_做测试的喵酱的博客-…

29. 求出商品连续售卖的时间区间

文章目录 题目需求思路一实现一题目来源 题目需求 从订单详情表&#xff08;order_detail&#xff09;中&#xff0c;求出商品连续售卖的时间区间。 期望结果如下&#xff1a; sku_id &#xff08;商品id&#xff09;start_date &#xff08;起始时间&#xff09;end_date &…

鸢尾花书简介

鸢尾花书简介 鸢尾花书 系列介绍1《编程不难》2《可视之美》3《数学要素》4《矩阵力量》5《统计至简》6《数据有道》7《机器学习》 重要链接 特别棒&#xff0c;极力推荐&#xff01;&#xff01;&#xff01; 鸢尾花书 系列介绍 1《编程不难》 《编程不难》&#xff1a;https:…

win11预览版更新,并尝试使用Copilot

文章目录 win11预览版更新&#xff0c;并使用Copilot先说结果所需内容具体操作更新操作系统版本更新Edge安装ViVeTool v0.3.3 测试Copilot问题唯一优点 总结 win11预览版更新&#xff0c;并使用Copilot 先说结果 体验一言难尽&#xff0c;就相当于是一个快捷聊天提问窗口。 自…

C语言实现WiFi数据收发(电脑作为服务器)

功能实现&#xff1a; 手机与电脑在一个局域网&#xff0c;实现手机与电脑之间数据收发。 主要是用socket协议完成功能。 电脑作为服务器&#xff0c;手机作为客户端 编程环境&#xff1a; 电脑端变成环境&#xff1a;VC6.0 手机端WiFi助手&#xff1a; 核心代码&#xff1a; …

K8S平台应用安全(Secret Service Ingress)

平台应用安全 1 平台应用安全1.1 敏感数据1.1.1 应用数据1.1.2 Secret基础1.1.3 Secret案例11.1.4 Secret案例2 1.2 数据访问1.2.1 网络体系解读1.2.2 Service实践1.2.3 Service进阶1.2.4 Service解读 1.3 应用流量1.3.1 Ingress基础1.3.2 Ingress实践1.3.3 Ingress进阶1.3.4 I…

用Python实现黑客代码

前言 用Python实现黑客代码&#xff0c;根本关不掉的窗口 &#x1f4dd;个人主页→数据挖掘博主ZTLJQ的主页 个人推荐python学习系列&#xff1a; ☄️爬虫JS逆向系列专栏 - 爬虫逆向教学 ☄️python系列专栏 - 从零开始学python 首先先介绍一下使用到的tkinter库 Tkinter 是 P…

通付盾联合嘶吼安全产业研究院共同发布《数据安全细分市场调研报告》并成功入选数据安全产业图谱多项细分领域,附报告!

7月4日&#xff0c;通付盾联合嘶吼安全产业研究院共同发布《时维鹰扬履践致远&#xff1a;数据安全细分市场调研报告2023》。 百炼露锋芒&#xff0c;本次《时维鹰扬履践致远&#xff1a;数据安全细分市场调研报告2023》聚焦数据安全市场细分领域市场规模、厂商玩法和产品竞争情…

二十三种设计模式第十四篇--策略模式

策略模式&#xff1a;主要围绕一个类的行为或者其算法在运行时更改&#xff0c;也是一种行为型模式。 在软件开发中&#xff0c;我们经常遇到需要根据不同的情况选择不同算法或行为的情况。传统的做法是使用大量的条件语句来实现这种逻辑&#xff0c;但这样的实现方式往往难以…

Numpy学习(参考)

目录 一、前言 二、numpy官方文档 文档划分 参数规范 相关知识明知 Routines学习(部分) 1、创建 2、数组操作常用 ufunc 三、numpy基本操作 开篇探索 数据类型 创建数组 创建数组有5种常规机制 常用创建方法 拷贝创建 数组运算 形状操作 查看形状 形状变换 …

第124天:内网安全-代理技术Socks协议路由不出网后渗透通讯CS-MSF上线

知识点 #知识点&#xff1a; 1、代理软件使用-Win&Linux 2、代理协议使用-Socks4/5 3、CS&MSF-网络通讯&控制上线-隧道技术&#xff1a;解决不出网协议上线的问题&#xff08;利用出网协议进行封装出网&#xff09; -代理技术&#xff1a;解决网络通讯不通的问题&…

MySQL数据库------------数据库的安装-----开始步入梦想

作者前言 欢迎小可爱们前来借鉴我的gtiee秦老大大 (qin-laoda) - Gitee.com —————————————————————————————————— 这一篇文章主要讲解一下MySQL的下载 数据库MySQL 这是 CentOS7 的 mysql 安装&#xff0c;如果有其他版本的需求&#xff…

C++ 环境设置

本地环境设置 如果您想要设置 C 语言环境&#xff0c;您需要确保电脑上有以下两款可用的软件&#xff0c;文本编辑器和 C 编译器。 文本编辑器 这将用于输入您的程序。文本编辑器包括 Windows Notepad、OS Edit command、Brief、Epsilon、EMACS 和 vim/vi。 文本编辑器的名…

tqdm笔记

目录 tqdm笔记导入显示进度条与enumerate一起使用 tqdm报错tqdm在notebook里每次刷新增加一行 tqdm笔记 导入 from tqdm import tqdm显示进度条 for i in tqdm(range(100)):time.sleep(0.01)与enumerate一起使用 a list(range(100)) for i, j in enumerate(tqdm(a)):time.…

Windows系统封装教程

一、封装前准备工作 虚拟机软件&#xff1a;VMware Workstation Pro windows镜像&#xff1a;windows 10.iso PE镜像&#xff1a;微PE.iso &#xff08;微PE工具箱&#xff09; 工具包&#xff1a;软媒魔方 封装工具&#xff1a;sysceo&#xff08;SC封装工具3.0&#xff…

java模拟面试题1

1、哪些问题是HTTPS无法解决的&#xff1f; Http是基于TCP协议的&#xff0c;在网络层的传输耗时比较长&#xff0c;https没有解决这个问题&#xff1b;http头是不能压缩的&#xff0c;每次要传递很大的数据包&#xff0c;每个连接也只能支持一个请求。同时https应用了很多加密…

IP地址定位在移动通信中的应用

根据IP地址定位技术在移动通信中的应用越发广泛。这项技术通过将用户的IP地址与地理位置信息相结合&#xff0c;为移动通信提供了更准确的定位服务。在这一创新中&#xff0c;移动通信运营商使用了IP地址定位技术以便更好地为用户提供定位服务、推送个性化广告以及提高安全性。…

数学建模常用模型(四):灰色关联分析法

数学建模常用模型&#xff08;四&#xff09;&#xff1a;灰色关联分析法 灰色关联分析法&#xff08;Grey Relational Analysis&#xff0c;GRA&#xff09;是一种用于多指标决策评价的方法&#xff0c;由灰色系统理论发展而来。它用于分析和评价多个指标之间的相关性和影响程…

【Python】矩阵乘法3种实现方案

结论&#xff1a; 1、 符在numpy里就是矩阵乘法的意思&#xff0c;也是dot()的意思。 2、用这个 运算符可以不用再使用matmult方法 3、一般来说&#xff0c; 比.dot()方法要慢一点点。dot是numpy里的函数&#xff0c;主要用于求向量相乘&#xff0c;矩阵乘法&#xff0c;矩…

vue通过mixins混入实现所有大屏适配,摆脱因适配引起的头痛(模版就是设计稿->全程就是px)

vue通过mixins混入实现所有大屏适配 市场上屏幕种类繁多&#xff0c;自己开发MAC的版本显示器1440900与另一个显示屏的全屏状态下是19201080&#xff0c;如何让自己的web项目&#xff0c;在不同的宽高比下依旧体现出高优越的观感体验。。。。 rem响应式单位:好用但是设计稿不…