03 MyBatisPlus之条件构造器Wrapper+三个核心注解

news2024/9/23 7:24:49

2. 条件构造器

2.1 条件构造器作用

//创建一个查询条件构造器对象,所有条件都放进去
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "John"); // eq添加等于条件
queryWrapper.ne("age", 30); // ne添加不等于条件
queryWrapper.like("email", "@gmail.com"); // like添加模糊匹配条件
等同于: 
delete from user where name = "John" and age != 30
                                  and email like "%@gmail.com%"
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

使用MyBatis-Plus的条件构造器,你可以构建灵活、高效的查询条件,而不需要手动编写复杂的 SQL 语句。它提供了许多方法来支持各种条件操作符,并且可以通过链式调用来组合多个条件。这样可以简化查询的编写过程,并提高开发效率。

2.2 条件构造器继承结构

条件构造器类结构:
在这里插入图片描述
Wrapper : 条件构造抽象类,最顶端父类

  • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
    • QueryWrapper : 查询/删除条件封装
    • UpdateWrapper : 修改条件封装
    • AbstractLambdaWrapper : 使用Lambda 语法
      • LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
      • LambdaUpdateWrapper : Lambda 更新封装Wrapper

2.3 基于QueryWrapper条件构造器

在这里插入图片描述

@Test
public void test01(){
    //查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息
    //SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (username LIKE '%a%' AND age >=20 AND age <=30 AND email IS NOT NULL)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
     /**普通调用,代码稍显冗长
     queryWrapper.like("username", "a")
     queryWrapper.between("age", 20, 30)
     queryWrapper.isNotNull("email");
     **/
    //链式调用
    queryWrapper.like("username", "a")
            .between("age", 20, 30)
            .isNotNull("email");
    //返回的对象可能是多个,故用selectList
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out:: println);

封装排序条件(orderByDesc/orderByAsc):

@Test
public void test02(){
    //按年龄降序查询用户,如果年龄相同则按id升序排列
    //SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,id ASC
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper
            .orderByDesc("age")
            .orderByAsc("id");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}

封装删除条件:(仍未QueryWrapper)

@Test
public void test03(){
    //删除email为空的用户
    //DELETE FROM t_user WHERE (email IS NULL)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNull("email");
    //条件构造器也可以构建删除语句的条件
    int result = userMapper.delete(queryWrapper);
    System.out.println("受影响的行数:" + result);
}

and和or关键字使用(修改):

@Test
public void test04() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改
    //UPDATE t_user SET age=18, email=user@sunsplanter.com WHERE username LIKE '%a%' OR email IS NULL AND age > 20)
    queryWrapper
            //(like or isnull) and gt
            .like("username", "a")
            .or()
            .isNull("email");
            .gt("age", 20)
    User user = new User();
    user.setAge(18);
    user.setEmail("user@sunsplanter.com");
    int result = userMapper.update(user, queryWrapper);
    System.out.println("受影响的行数:" + result);
}

指定列映射查询(select):

@Test
public void test05() {
    //查询用户信息的username和age字段
    //SELECT username,age FROM t_user
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.select("username", "age");
    //selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值为null
    List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
    maps.forEach(System.out::println);
}

condition实现条件判断,可以叠加上述所有语句使用

 @Test
public void testQuick3(){
    
    String name = "root";
    int    age = 18;

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //当name不为null, age > 1 时,才允许作为条件添加进构造器,一个作为相等判断,一个作为大于判断
    //例如仅当前端传来的name不为空时,才判断是否相等
    //方案1: 手动判断
    if (!StringUtils.isEmpty(name)){
        queryWrapper.eq("name",name);
    }
    if (age > 1){
        queryWrapper.gt("age",age);
    }
    
    //方案2: 拼接condition判断.格式为eq(condition,列名,值)
    //每个条件拼接方法都condition参数,这是一个比较运算,为true追加当前条件!
   //仅当name非空时,才加入name = root条件进构造器中
    queryWrapper.eq(!StringUtils.isEmpty(name),"name",name)
            .gt(age>1,"age",age);   
}

2.4 基于 UpdateWrapper条件构造器

使用queryWrapper进行更新的两个问题
a. 要准备一个实体类,将要改成的数据放入实体类
b. 原本为null的数据改不了(update方法只能改非空的数据)

@Test
public void test04() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改
    //UPDATE t_user SET age=18, email=user@sunsplanter.com WHERE username LIKE '%a%' AND age > 20 OR email IS NULL)
    queryWrapper
            .like("username", "a")
            .gt("age", 20)
            .or()
            .isNull("email");
    //要修改成下列数据
    User user = new User();
    user.setAge(18);
    user.setEmail("user@sunsplanter.com");
    int result = userMapper.update(user, queryWrapper);
    System.out.println("受影响的行数:" + result);
}

使用updateWrapper:
a. 直接携带修改数据,无需声明实体对象
b. 指定任意修改值

@Test
public void testQuick2(){

    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    //将id = 3 的email设置为null, age = 18
    updateWrapper.eq("id",3)
            .set("email",null)  // set 指定列和结果
            .set("age",18);
    //如果使用updateWrapper 实体对象写null即可!
    int result = userMapper.update(null, updateWrapper);
    System.out.println("result = " + result);

}

LambdaQueryWrapper属于QueryWrapper
LambdaUpdateWrapper属于UpdateWrapper
用法一样 , 功能增强 , 类似MB与MP


2.5 基于LambdaQueryWrapper组装条件

LambdaQueryWrapper对比QueryWrapper优势

QueryWrapper 示例代码:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "John")
  .ge("age", 18)
  .orderByDesc("create_time")
  .last("limit 10");
List<User> userList = userMapper.selectList(queryWrapper);

LambdaQueryWrapper 示例代码:

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();

lambdaQueryWrapper.eq(User::getName, "John")
  .ge(User::getAge, 18)
  .orderByDesc(User::getCreateTime)
  .last("limit 10");
List<User> userList = userMapper.selectList(lambdaQueryWrapper);
从上面的代码对比可以看出,相比于 QueryWrapper,LambdaQueryWrapper 使用了实体类的属性引用(例如 `User::getName`、`User::getAge`),
而不是字符串来表示字段名,这提高了代码的可读性和可维护性。

2.6 方法引用回顾:

方法引用是 Java 8 中引入的一种语法特性,它提供了一种简洁的方式来直接引用已有的方法或构造函数。方法引用可以替代 Lambda 表达式,使代码更简洁、更易读。

Java 8 支持以下几种方法引用的形式:

1. 静态方法引用: 引用静态方法,语法为 `类名::静态方法名`。
2. 实例方法引用: 引用实例方法,语法为 `实例对象::实例方法名`。
3. 对象方法引用: 引用特定对象的实例方法,语法为 `类名::实例方法名`。
4. 构造函数引用: 引用构造函数,语法为 `类名::new`。

演示代码:

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class MethodReferenceExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("John", "Tom", "Alice");
        // 使用 Lambda 表达式
        names.forEach(name -> System.out.println(name));
        // 使用方法引用
        names.forEach(System.out::println);
    }
}

lambdaQueryWrapper使用案例:

@Test
public void testQuick4(){

    String name = "root";
    int    age = 18;

    //使用QueryWrapper
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //每个条件拼接方法都condition参数,这是一个比较运算,为true追加当前条件!
    //eq(condition,列名,值)
    queryWrapper.eq(!StringUtils.isEmpty(name),"name",name)
            .eq(age>1,"age",age);

    // 使用lambdaQueryWrapper
    LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    //注意: 需要使用方法引用
    //技巧: 类名::方法名
    lambdaQueryWrapper.eq(!StringUtils.isEmpty(name), User::getName,name);
    List<User> users= userMapper.selectList(lambdaQueryWrapper);
    System.out.println(users);
}

LambdaUpdateWrapper使用案例

@Test
public void testQuick2(){

    //使用UpdateWrapper
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    //将id = 3 的email设置为null, age = 18
    updateWrapper.eq("id",3)
            .set("email",null)  // set 指定列和结果
            .set("age",18);

    //使用lambdaUpdateWrapper
    LambdaUpdateWrapper<User> updateWrapper1 = new LambdaUpdateWrapper<>();
    updateWrapper1.eq(User::getId,3)
            .set(User::getEmail,null)
            .set(User::getAge,18);
    
    //如果使用updateWrapper 实体对象写null即可!
    int result = userMapper.update(null, updateWrapper);
    System.out.println("result = " + result);
}

3. 核心注解使用

3.1 @TableName注解

  - 描述:表名注解,将实体类和表绑定(用于实体类名和xxxMapper.java的xxx不匹配时)
  - 一个最简单的例子是,数据库表一般都是t_xxx,但实体类不会有t,这时二者就不匹配了
  - 使用位置:实体类
public interface UserMapper extends BaseMapper<User> {

}

此接口对应的方法为什么会自动触发 user表的crud呢?

默认情况下, 根据指定的<实体类>的名称对应数据库表名,属性名对应数据库的列名!

但是不是所有数据库的信息和实体类都完全映射!

例如: 表名 t_user → 实体类 User 这时候就不对应了!

@TableName("sys_user") //对应数据库表名
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

特殊情况:如果表名和实体类名相同(忽略大小写)可以省略该注解!

其他解决方案:全局设置前缀

mybatis-plus: # mybatis-plus的配置
  global-config:
    db-config:
    #所有的实体类xxx都与sys_xxx表名自动匹配
      table-prefix: sys_ # 表名前缀字符串

3.1 @TableId 注解

  • 描述:主键注解
  • 使用位置:实体类主键字段之上
  • 使用情况:
    a.主键的字段名和属性名不一致,用value属性绑定二者
    b.插入数据时,用type属性指定生成主键的策略

在这里插入图片描述在这里插入图片描述

实体类:

@TableName("sys_user")
public class User {
    //主键自增长,使用的前提是数据库中的主键字段必须提前设置了自增长
    @TableId(value="主键列名",type = IdType_AUTO)
    private Long id;
    private String name;
    private Integer age;
}

测试方法:

public void testTableId(){.
	User user = new User();
	user.setName("zhangsan");
	user.setAge(20);
	userMapper.insert(user);
}

会成功插入一条数据,其中id字段为默认的雪花算法生成的。

当然,也可以全局配置修改主键策略:

mybatis-plus:
  configuration:
    # 配置MyBatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 配置MyBatis-Plus操作表的默认前缀
      table-prefix: t_
      # 配置MyBatis-Plus的主键策略
      id-type: auto

雪花算法:

  **你需要记住的: 雪花算法生成的数字,需要使用Long 或者 String类型主键!!**

  雪花算法(Snowflake Algorithm)是一种用于生成唯一ID的算法 , 用于解决分布式系统中生成全局唯一ID的需求。

  在传统的自增ID生成方式中,使用单点数据库生成ID会成为系统的瓶颈,而雪花算法通过在分布式系统中生成唯一ID,避免了单点故障和性能瓶颈的问题。

  雪花算法生成的ID是一个64位的整数,由以下几个部分组成:

  1. 时间戳:41位,精确到毫秒级,可以使用69年。
  2. 节点ID:10位,用于标识分布式系统中的不同节点。
  3. 序列号:12位,表示在同一毫秒内生成的不同ID的序号。

  通过将这三个部分组合在一起,雪花算法可以在分布式系统中生成全局唯一的ID,并保证ID的生成顺序性。

  雪花算法的工作方式如下:

  1. 当前时间戳从某一固定的起始时间开始计算,可以用于计算ID的时间部分。
  2. 节点ID是分布式系统中每个节点的唯一标识,可以通过配置或自动分配的方式获得。
  3. 序列号用于记录在同一毫秒内生成的不同ID的序号,从0开始自增,最多支持4096个ID生成。

  需要注意的是,雪花算法依赖于系统的时钟,需要确保系统时钟的准确性和单调性,否则可能会导致生成的ID不唯一或不符合预期的顺序。

  雪花算法是一种简单但有效的生成唯一ID的算法,广泛应用于分布式系统中,如微服务架构、分布式数据库、分布式锁等场景,以满足全局唯一标识的需求。
  1. @TableField
  • 描述:字段注解(非主键)

  • 使用场景 :
    a. 区分该字段是否在数据库中存储.有一些字段仅在程序运行过程中存在 , 不需要持久化保存 ,于是提前声明这个字段不存在表里 , 不要去表里找.
    b. 绑定实体属性和表的字段

    在这里插入图片描述

@TableName("sys_user")
public class User {
    @TableId
    private Long id;
    @TableField("nickname")
    private String name;
    private Integer age;
    @TableField(exist = false)
    private String email;
}

MyBatis-Plus会自动开启驼峰命名风格映射!!!

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

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

相关文章

伊恩·斯图尔特《改变世界的17个方程》波动方程笔记

主要是课堂的补充&#xff08;yysy&#xff0c;我觉得课堂的教育模式真有够无聊的&#xff0c;PPT、写作业、考试&#xff0c;感受不到知识的魅力。 它告诉我们什么&#xff1f; 小提琴琴弦上某个小段的加速度&#xff0c;与相邻段相对于该段的平均位移成正比。 为什么重要&…

初阶数据结构:顺序表

目录 1. 引子&#xff1a;线性表2. 简单数据结构&#xff1a;顺序表2.1 顺序表简介与功能模块分析2.2 顺序表的实现2.2.1 顺序表&#xff1a;存储数据结构的构建2.2.2 顺序表&#xff1a;初始化与空间清理&#xff08;动态&#xff09;2.2.3 顺序表&#xff1a;插入与删除数据2…

总结网络中的一些基本概念

1. IP地址 描述一个设备在网络上的位置&#xff0c;而且计算机是通过数字来描述IP地址的。例如&#xff08;生活中的地址&#xff09; 2. 端口号 描述一个主机上的哪个应用程序&#xff0c;有了IP可以确定主机&#xff0c;但是一个主机上可能有很多程序在使用网络&#xff0c;…

基于SpringBoot Vue自习室管理系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

Elasticsearch各种高级文档操作3

本文来记录几种Elasticsearch的文档操作 文章目录 初始化文档数据聚合查询文档概述对某个字段取最大值 max 示例对某个字段取最小值 min 示例对某个字段求和 sum 示例对某个字段取平均值 avg 示例对某个字段的值进行去重之后再取总数 示例 本文小结 初始化文档数据 在进行各种文…

ASP.NET Core 对象池化技术

写在前面 Microsoft.Extensions.ObjectPool 是 ASP.NET Core 基础结构的一部分&#xff0c;当对象的初始化成本较高&#xff0c;并且可能被频繁使用时&#xff0c;才适合采用对象池技术&#xff1b;被ObjectPool管理的对象不会进入垃圾回收&#xff0c;使用时通过由实例对象实…

【迅搜19】扩展(二)TNTSearch和JiebaPHP方案

扩展&#xff08;二&#xff09;TNTSearch和JiebaPHP方案 搜索引擎系列的最后一篇了。既然是最后一篇&#xff0c;那么我们也轻松一点&#xff0c;直接来看一套非常有意思的纯 PHP 实现的搜索引擎及分词方案吧。这一套方案由两个组件组成&#xff0c;一个叫 TNTSearch &#xf…

【0到1的设计之路】从C语言到二进制程序

C程序如何从源代码生成指令序列(二进制可执行文件) 预处理 -> 编译 -> 汇编 -> 链接 -> 执行 预处理 预处理 文本粘贴 #include <stdio.h> #define MSG "Hello \ World!\n" int main() {printf(MSG /* "hi!\n" */); #ifdef __riscvpr…

PE解释器之PE文件结构(二)

接下来的内容是对IMAGE_OPTIONAL_HEADER32中的最后一个成员DataDirectory&#xff0c;虽然他只是一个结构体数组&#xff0c;每个结构体的大小也不过是个字节&#xff0c;但是它却是PE文件中最重要的成员。PE装载器通过查看它才能准确的找到某个函数或某个资源。 一&#xff1…

2种数控棋

目录 数控棋1 数控棋2 数控棋1 棋盘&#xff1a; 初始局面&#xff1a; 规则&#xff1a; 规则&#xff1a;双方轮流走棋&#xff0c;可走横格、竖格、可横竖转弯&#xff0c;不可走斜格。每一步均须按棋所在格的数字走步数&#xff0c;不可多不可少。 先无法走棋的一方为…

如何有效防爬虫?一文讲解反爬虫策略

企业拥抱数字化技术的过程中&#xff0c;网络犯罪分子的“战术”也更难以觉察&#xff0c;并且这些攻击越来越自动化和复杂&#xff0c;也更加难以觉察。在众多攻击手段中&#xff0c;网络爬虫是企业面临的主要安全挑战。恶意爬虫活动可能导致数据滥用、盗窃商业机密等问题&…

ctfshow php特性(web89-web101)

目录 web89 web90 web91 web92 web93 web94 web95 web96 web97 web98 web99 web100 web101 php特性(php基础知识) web89 <?php include("flag.php"); highlight_file(_FILE_);if(isset($_GET[num])){$num$_GET[num];if(preg_match("/[0-9]/&…

ffmpeg 常用命令行详解

概述 ffmpeg 是一个命令行音视频后期处理软件 1. 裁剪命令 参数说明 -i 文件&#xff0c;orgin.mp3 为待处理源文件-ss 裁剪时间&#xff0c;后跟裁剪开始时间&#xff0c;或者开始的秒数-t 裁剪时间output.mp3 为处理结果文件 ffmpeg -i organ.mp3 -ss 00:00:xx -t 120 o…

Oracle 隐式数据类型转换

目录 Oracle类型转换规则&#xff1a; 看如下实验&#xff1a; 1、创建一张表&#xff0c;字段id的类型为number&#xff0c;id字段创建索引&#xff0c;插入一条测试数据 2、我们做如下查询&#xff0c;id的值设置为字符型的1 3、查看执行计划&#xff1a; Oracle类型转换…

MySQL之索引结构

索引概述 索引是帮助MySQL高效获取数据的数据结构&#xff08;有序&#xff09;。 在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0c;这样就可以在这些数据结构上实现…

JMeter实操入门之登录

JMeter实操入门之登录 前言初级-无变量的登录线程组取样器-HTTP请求 进阶-定义变量的登录用户定义的变量获取JSON返回的数据-tokentoken设置全局变量 前言 安装及环境配置教程可移步&#xff1a;JMeter安装与配置环境 本篇文章针对小白进一步的认识及运用JMeter&#xff0c;围绕…

从数据角度分析年龄与NBA球员赛场表现的关系【数据分析项目分享】

好久不见朋友们&#xff0c;今天给大家分享一个我自己很感兴趣的话题分析——NBA球员表现跟年龄关系到底大不大&#xff1f;数据来源于Kaggle&#xff0c;感兴趣的朋友可以点赞评论留言&#xff0c;我会将数据同代码一起发送给你。 目录 NBA球员表现的探索性数据分析导入Python…

ChatGPT与文心一言:AI助手之巅的对决

随着科技的飞速发展&#xff0c;人工智能助手已经渗透到我们的日常生活和工作中。 而在这个充满竞争的领域里&#xff0c;ChatGPT和文心一言无疑是最引人注目的两款产品。它们各自拥有独特的优势&#xff0c;但在智能回复、语言准确性、知识库丰富度等方面却存在差异。那么&am…

【设计模式】责任连模式怎么用?

我将通过一个贴近现实的故事——请假审批流程&#xff0c;带你了解和掌握责任链模式。 什么是责任链模式&#xff1f; 责任链模式是一种行为设计模式&#xff0c;它让你可以避免将请求的发送者与接收者耦合在一起&#xff0c;让多个对象都有处理请求的机会将这个对象连成一条…

RabbitMQ入门篇【图文并茂,超级详细】

&#x1f973;&#x1f973;Welcome 的Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Docker的相关操作吧 目录 &#x1f973;&#x1f973;Welcome 的Huihuis Code World ! !&#x1f973;&#x1f973; 前言 1.什么是MQ 2.理解MQ 3.生活…