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

news/2024/11/16 10:32:27/

玄子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 TransferSource Server         : XuanZiSource Server Type    : MySQLSource Server Version : 50740 (5.7.40)Source Host           : localhost:3306Source Schema         : userTarget Server Type    : MySQLTarget Server Version : 50740 (5.7.40)File Encoding         : 65001Date: 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.Driverusername: rootpassword: rooturl: 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 {@Autowiredprivate UserMapper userMapper;@Testvoid contextLoads() {List<User> patients = userMapper.selectList(null);patients.forEach(System.out::println);}
}

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

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

基础 CRUD

新增

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

修改

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

通过 id 修改传递 user 对象

删除

    @Testvoid deleteById() {int i = userMapper.deleteById(2);System.out.println(i);contextLoads();}@Testvoid deleteBatchIds() {int i = userMapper.deleteBatchIds(Arrays.asList(1, 4));System.out.println(i);contextLoads();}@Testvoid 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

查询

    @Testvoid selectByid() {User result = userMapper.selectById(7);System.out.println(result);}@Testvoid selectBatchIds() {List<User> result = userMapper.selectBatchIds(Arrays.asList(1, 2, 4, 9));result.forEach(System.out::println);}@Testvoid 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注解

 @TableLogicprivate int deleted;

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

分页查

    @Testvoid 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 {@Overridepublic void insertFill(MetaObject metaObject) {log.info("start insertFill");this.setFieldValByName("insertTime", new Date(), metaObject);this.setFieldValByName("updateTime", new Date(), metaObject);}@Overridepublic 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.ppmy.cn/news/735707.html

相关文章

计算机所有接口都没反应,如何解决Win7系统USB接口没反应的问题

电脑USB接口不能用&#xff0c;没反应是电脑最常见的问题之一了&#xff0c;也是绝大部分人都会出现的问题。但是&#xff0c;最近有使用Win7系统的用户说自己电脑的USB接口没反应不能使用&#xff0c;插入U盘等待半天都没有反应&#xff0c;哪里出现问题呢&#xff1f;U盘插入…

普通u盘linux不识别,Linux识别不了u盘怎么办

在Linux系统中&#xff0c;有时插上u盘却无法识别&#xff0c;想必不少人遇到过这个问题&#xff0c;而Linux不会自动更新驱动&#xff0c;遇到这种问题该如何解决呢?下面小编就给大家介绍下Linux无法识别u盘的解决方法&#xff0c;一起来了解下吧。 方法 一、插入u盘到计算机…

u盘插电脑计算机卡了,U盘连接电脑后出现卡顿怎么回事_U盘连接电脑后电脑非常卡如何处理-win7之家...

大家都喜欢将U盘连接电脑来拷贝文件或者装系统&#xff0c;不过近日有用户将U盘插入电脑连接之后&#xff0c;发现电脑会出现卡顿的情况&#xff0c;很多用户遇到这样的问题都不知道要怎么办&#xff0c;为此&#xff0c;本文就给大家讲述一下U盘连接电脑后电脑非常卡的详细解决…

u盘插到电脑计算机里没有反应,U盘插在Windows7电脑上没反应怎么办?

我们在使用U盘时&#xff0c;偶尔会遇到U盘插入电脑没有反应的问题。比如此前有一个网友在它的Win7系统电脑上插入U盘&#xff0c;反复尝试都没有反应。遇到这种问题&#xff0c;我们该怎么解决呢? 1.在Windows资源管理器中&#xff0c;进入到“系统盘:\WINDOWS\inf”目录&…

单元测试基础

一、什么是单元测试&#xff1a; 单元测试是指&#xff0c;对软件中的最小可测试单元在与程序其他部分相隔离的情况下进行检查和验证的工作&#xff0c;这里的最小可测试单元通常是指函数或者类&#xff1b;单元测试属于最严格的软件测试手段&#xff0c;是最接近代码底层实现…

远航汽车:坚持合作共赢经营理念 携手志同道合者共创美好未来

智能汽车时代&#xff0c;想要打造一款真正符合用户需求的新能源车&#xff0c;势必要具备硬核技术实力以及敢于突破、不断求变的思维&#xff0c;始终做到以用户为中心&#xff0c;打造属于自己的品牌核心力&#xff0c;才能从激烈的市场竞争中脱颖而出。在此背景下&#xff0…

Fluent1000万网格需要多大内存

三维网格&#xff0c;1000w网格需要的内存大概40G左右 来源知乎

如果你负责一款DAU(日活用户数量)1000W左右的陌生交友类社交产品,你会怎样从用户角度分析变现空间?

首先可能要对该app的用户进行一个基本的用户分析和画像定位。再去选择哪种变现方式比较合适。 DAU达到1000W左右&#xff0c;说明这已经是一款踏入成熟期的产品&#xff0c;核心功能不再考虑大变动而是考虑优化升级、找到新的增长点&#xff1b; 陌生交友类社交产品&#xff0c…