MyBatis-Plus深入 —— 条件构造器与插件管理

news2024/12/29 9:47:56

前言

        在前面的文章中,荔枝梳理了一个MyBatis-Plus的基本使用、配置和通用Service接口,我们发现在MyBatis-Plus的辅助增强下我们不再需要通过配置xml文件中的sql语句来实现基本的sql操作了,不愧是最佳搭档!在这篇文章中,荔枝会着重梳理有关MyBatis-Plus的两个知识点:条件构造器、分页插件和乐观锁插件,希望对有需要的小伙伴有帮助~~~


文章目录

前言

一、条件构造器

1.1 组装查询条件

1.2 组装排序条件

1.3 组装删除条件

1.4 使用QueryWrapper实现修改功能 

1.5 条件优先级

1.6 子查询

1.7 使用UpdateWrapper实现修改功能

1.8 使用Condition组装条件

1.9 LambdaQueryWrapper

1.10 LambdaUpdateWrapper 

二、分页插件

2.1 基本使用 

2.2 自定义分页插件 

三、乐观锁插件

3.1 乐观锁和悲观锁

3.2 乐观锁插件

总结


一、条件构造器

        条件构造器,顾名思义就是用来封装当前我们用来查询的条件的,条件构造器的最顶层的接口是Mapper,被AbstractWrapper继承,其下由三个子类分别是:AbstractLambdaWrapper、UpdateWrapper和QueryWrapper。

1.1 组装查询条件

//条件构造器组装查询条件
    @Test
    public void testWrapper(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name","crj")
                .between("age",20,30)
                .isNotNull("email");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.2 组装排序条件

//组装排序条件
    @Test
    public void test1(){
        //查询用户信息按照年龄的降序排序,若年龄相同则按照id升序排序
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age")
                .orderByAsc("uid");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.3 组装删除条件

//组装删除条件
    @Test
    public void test2(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println("受影响函数"+result);
    }

1.4 使用QueryWrapper实现修改功能 

//实现修改功能
    @Test
    public void  test3(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //把年龄大于20且姓名为crj或者是邮箱为null的用户信息进行修改
        queryWrapper.gt("age",20)
                .like("user_name","crj")
                .or()
                .isNull("email");
        User user = new User();
        user.setName("CRJ");
        user.setEmail("123456@123.com");
        int result = userMapper.update(user,queryWrapper);
        System.out.println(result);
    }

1.5 条件优先级

在and()和or()中通过Lambda表达式实现优先级操作,其中Lambda表达式中的条件优先执行。

 //条件优先级
    @Test
    public  void test4(){
        //将用户名中含有crj并且(年龄大于20或邮箱为null)的用户信息修改
        //lambda中的条件优先执行
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name","crj")
                .and(i->i.gt("age",20).or().isNull("email"));
        User user = new User();
        user.setName("CRJ");
        user.setEmail("123456@123.com");
        int result = userMapper.update(user,queryWrapper);
        System.out.println(result);
    }

1.6 子查询

//子查询
    @Test
    public void test5(){
        //查询id小于等于100的用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("uid","select uid from t_user where uid<=100");
        List<User> list = userMapper.selectList(queryWrapper);
    }

1.7 使用UpdateWrapper实现修改功能

//使用UpdateWrapper实现修改功能
//将用户名中含有crj并且(年龄大于20或邮箱为null)的用户信息修改
    @Test
    public  void  test6(){
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.like("user_name","crj")
                .and(i->i.gt("age",20).or().isNull("email"));
        updateWrapper.set("user_name","CRJ");
        userMapper.update(null,updateWrapper);
    }

1.8 使用Condition组装条件

1.9 LambdaQueryWrapper

    @Test
    public void test8(){
        String username = "a";
        Integer ageBegin = null;
        Integer ageEnd = 30;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
                .ge(ageBegin!=null,User::getAge,ageBegin)
                .le(ageEnd!=null,User::getAge,ageEnd);
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.10 LambdaUpdateWrapper 

    @Test
    public  void  test9(){
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.like(User::getName,"crj")
                .and(i->i.gt(User::getAge,20).or().isNull(User::getEmail));
        updateWrapper.set(User::getName,"CRJ");
        userMapper.update(null,updateWrapper);
    }

二、分页插件

2.1 基本使用 

 分页插件的配置类

package com.crj.mybatisplus_test.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//配置类,配置MyBatisPlus的插件功能
@Configuration
@MapperScan("com.crj.mybatisplus_test.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

测试类

package com.crj.mybatisplus_test;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crj.mybatisplus_test.mapper.UserMapper;
import com.crj.mybatisplus_test.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class MyBatisPlusPluginsTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void test1(){
        Page<User> page = new Page<>(1,3);
        userMapper.selectPage(page,null);
        System.out.println(page);
    }
}

page对象的几个方法:

  • page.getRecords(): 获取当前页数据
  • page.getCurrent():获取当前页的页码
  • page.getSize():获取每页显示的条数
  • page.getPages(): 获取总页数
  • page.getTotal(): 获取总记录数
  • page.hasNext(): 查看有没有下一页
  • page.hasPrevious():查看有没有上一页

配置类型别名:

mybatis-plus:

        type-aliases-package:全路径 

2.2 自定义分页插件 

        之前借助条件构造器来实现分页的操作,通过查看源码知晓,selectPage要求两个参数,返回值和第一个参数都是IPage类型的,而IPage类型的接口是被Page类对象实现的,因此第一个参数一定是page对象。我们需要在userMapper接口中手写一个方法替代原来的selectPage,同时分页插件的配置文件保持不变,配置好MyBatisPlus的插件功能

UserMapper.java 

package com.crj.mybatisplus_test.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crj.mybatisplus_test.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;


@Repository
//继承MyBatis-Plus的BaseMapper接口
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据年龄查询用户信息并分页
     * @param page mybatis-plus提供的分页对象,必须放在第一个参数中
     * @param age
     * @return
     */
    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
}

UserMapper.xml 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.crj.mybatisplus_test.mapper.UserMapper">

<!--    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);-->
    <select id="selectPageVo" resultType="User">
        select uid,name,age from t_user where age > #{age}
    </select>
</mapper>

测试类

    @Test
    public void testPageVo(){
        Page<User> page = new Page<>(1,3);
        userMapper.selectPageVo(page,20);
    }

三、乐观锁插件

3.1 乐观锁和悲观锁

        说到乐观锁和悲观锁,我们经常通过一个场景来理解:我们需要对一个值为100的数进行+10操作再进行-30操作,这两步使用多线程执行。A和B线程同时取一个值为100的数C,A对C进行+10操作,B对取出来的值进行-30的操作,如果没有加锁控制,那么A处理的值D不能被B拿到且会被B覆盖。对于加锁这里简单归纳两种:乐观锁和悲观锁,悲观锁会格外注重线程安全,只有等A操作完后才能由B取值;而乐观锁则是通过版本控制的方式来检测是否C被修改了。

未加锁的场景模拟

实体类

package com.crj.mybatisplus_test.pojo;

import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    private Integer version;

}

mapper接口

package com.crj.mybatisplus_test.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.springframework.stereotype.Service;

@Service
public interface ProductMapper extends BaseMapper<Product> {

}

测试类

package com.crj.mybatisplus_test;

import com.crj.mybatisplus_test.mapper.ProductMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

//乐观锁插件使用
@SpringBootTest
public class MyBatisLockTest {
    @Autowired
    private ProductMapper productMapper;
    //模拟线程场景
    @Test
    public void test1(){
        Product productA = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productA.getPrice());
        Product productB = productMapper.selectById(1);
        System.out.println("B查询的商品价格"+productB.getPrice());

        productA.setPrice(productA.getPrice()+10);
        productMapper.updateById(productA);
        productB.setPrice(productB.getPrice()-30);
        productMapper.updateById(productB);
        //最后结果
        Product productC = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productC.getPrice());

    }
}

3.2 乐观锁插件

前面知道乐观锁实现需要加上版本号来控制,因此实体类需要进行通过@Version来设置版本号。

实体类

package com.crj.mybatisplus_test.pojo;

import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;

    @Version //标识乐观锁版本号字段
    private Integer version;

}

MyBatis-Plus插件配置类

需要在配置类中配置好乐观锁插件方法OptimisticLockerInnerInterceptor()

package com.crj.mybatisplus_test.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//配置类,配置MyBatisPlus的插件功能
@Configuration
@MapperScan("com.crj.mybatisplus_test.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //配置分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //配置乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

测试类

需要注意的是B修改数据失败后需要重试即可完成任务需求。 

package com.crj.mybatisplus_test;

import com.crj.mybatisplus_test.mapper.ProductMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

//乐观锁插件使用
@SpringBootTest
public class MyBatisLockTest {
    @Autowired
    private ProductMapper productMapper;
    //模拟线程场景
    @Test
    public void test1(){
        Product productA = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productA.getPrice());
        Product productB = productMapper.selectById(1);
        System.out.println("B查询的商品价格"+productB.getPrice());

        productA.setPrice(productA.getPrice()+10);
        productMapper.updateById(productA);
        productB.setPrice(productB.getPrice()-30);
        int result = productMapper.updateById(productB);

        //由于加入了版本号控制,因此需要对修改失败的操作进行重试
        if(result==0){
            //失败重试
            Product productNew = productMapper.selectById(1);
            productNew.setPrice(productNew.getPrice()-30);
            productMapper.updateById(productNew);
        }
        //最后结果
        Product productC = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productC.getPrice());

    }
}

总结

        通过条件构造器的几种基本用法使用示例,荔枝对wrapper类的使用有了一个比较直观的理解,同时荔枝觉得更需要注意的是两种插件的使用。接下来的文章中荔枝会对MyBatis-Plus的相关基础知识收尾,同时尝试整合到学习的项目中,跟荔枝一起期待一波吧哈哈哈哈哈~~~

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

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

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

相关文章

ping: www.baidu.com: Name or service not known 写了DNS还是不行

环境描述&#xff1a;ESXI平台上&#xff0c;一台Centos7虚拟主机。 问题描述&#xff1a;平台上的其他的虚拟机可以正常ping通&#xff0c;就这台ping IP地址可以通&#xff0c;ping域名解析失败。 排查过程&#xff1a; 1、检查网卡配置文件和/etc/resolv.conf配置文件是否…

【综述+3D】基于NeRF的三维视觉2023年度进展报告(截止2023.06.10)

论文&#xff1a;2003.Representing Scenes as Neural Radiance Fields for View Synthesis 官方网站&#xff1a;https://www.matthewtancik.com/nerf 突破性后续改进&#xff1a; Instant Neural Graphics Primitives with a Multiresolution Hash Encoding | 展示官网&#…

K8S的介绍和架构

仅供入门 K8S的介绍和架构 一. 什么是kubernetes二、Kubernetes架构和组件 2.1 核心组件 2.1.1 Kubernetes Master控制组件&#xff0c;调度管理整个系统&#xff08;集群&#xff09;&#xff0c;包含如下组件: a、Kubernetes API Serverb、Kubernetes Schedulerc、Kubernet…

【前端】CSS-Grid网格布局

目录 一、grid布局是什么二、grid布局的属性三、容器属性1、display①、语句②、属性值 2、grid-template-columns属性、grid-template-rows属性①、定义②、属性值1&#xff09;、固定的列宽和行高2&#xff09;、repeat()函数3&#xff09;、auto-fill关键字4&#xff09;、f…

Vue指令之战:v-if vs. v-show -你应该使用哪一个?

在Vue.js中&#xff0c;条件渲染是一项常见任务&#xff0c;而v-if和v-show是两个最常用的指令。这两个指令在实现方式上有所不同&#xff0c;对于开发者来说选择正确的指令可能具有挑战性。本文将深入探讨Vue 2和Vue 3中的v-if和v-show指令的区别&#xff0c;并结合实际应用场…

Linux的命令

Linux的命令分为四个类型&#xff1a;文件操作命令、系统操作命令、文本处理命令和网络操作命令。下面简单介绍一下常用的Linux命令&#xff1a; 文件操作命令 ls&#xff1a;列出目录下的所有文件和目录。 cd&#xff1a;切换当前目录。 mkdir&#xff1a;创建一个新目录。…

<图像处理> 可分离滤波器核

可分离滤波器核 空间滤波器核是一个二维矩阵&#xff0c;若它能够表示为两个一维矩阵的乘积时&#xff0c;则表示该滤波器核是可分离的。 例如&#xff0c;一个3x3的核&#xff0c; w [ 1 1 1 1 1 1 1 1 1 ] w\begin{bmatrix} 1 & 1 & 1\\ 1 & 1& 1\\ 1 &am…

操作系统(OS)与系统进程

操作系统&#xff08;OS&#xff09;与系统进程 冯诺依曼体系结构操作系统(Operator System)进程基本概念进程的描述&#xff08;PCB&#xff09;查看进程通过系统调用获取进程标示符&#xff08;PID&#xff09;通过系统调用创建进程&#xff08;fork&#xff09;进程状态&…

安防监控/视频汇聚/云存储/AI智能视频融合平台页面新增地图展示功能

AI智能分析网关包含有20多种算法&#xff0c;包括人脸、人体、车辆、车牌、行为分析、烟火、入侵、聚集、安全帽、反光衣等等&#xff0c;可应用在安全生产、通用园区、智慧食安、智慧城管、智慧煤矿等场景中。将网关硬件结合我们的视频汇聚/安防监控/视频融合平台EasyCVR一起使…

使用Python进行健身手表数据分析

健身手表(Fitness Watch)数据分析涉及分析健身可穿戴设备或智能手表收集的数据&#xff0c;以深入了解用户的健康和活动模式。这些设备可以跟踪所走的步数、消耗的能量、步行速度等指标。本文将带您完成使用Python进行Fitness Watch数据分析的任务。 Fitness Watch数据分析是健…

QT多线程

1.QT4.7以前的版本-----线程处理方式 1. 出现的警告 直接使用从UI—>转到槽&#xff0c;就会出现警告 2. 出现的错误 error: invalid operands of types QTimer* and void (QTimer::*)(QTimer::QPrivateSignal) to binary operator& 错误:无效的操作数类型’QTimer…

【人工智能】—_有信息搜索、最佳优先搜索、贪心搜索、A_搜索

文章目录 【人工智能】— 有信息搜索、最佳优先搜索、贪心搜索、A*搜索无/有信息的搜索Informed Search AlgorithmsBest-first search(最佳优先搜索)Greedy SearchA* Search解释说明A*搜索是代价最优的和完备的对搜索等值线如何理解 【人工智能】— 有信息搜索、最佳优先搜索、…

2023年文旅地产行业研究报告

第一章 行业概况 1.1 定义 文旅地产&#xff0c;作为一个综合性的产业形态&#xff0c;融合了文化、旅游和地产三大元素&#xff0c;是住宅地产的补充和延伸。它不仅包含了文化和旅游的业态&#xff0c;还融入了商业等多元化元素&#xff0c;被誉为地产中的轻奢品。 在核心业…

AVR128单片机 自动售水机

一、系统方案 1、设计使用两个按键分别为S1和S2及一个发光二极管LED。S1为出水控制按键&#xff0c;当S1按下&#xff0c;表示售水机持续出水&#xff0c;继电器&#xff08;库元件relay&#xff09;接通&#xff0c;指示灯LED亮。S2为停水控制键&#xff0c;当S2按下&#xff…

Jenkins详解(三)

Jenkins详解(三) 目录 Jenkins详解(三) 1、Jenkins介绍2、Jenkins CI/CD 流程3、部署环境 3.1 环境准备3.2 安装GitLab3.3 初始化GitLab3.4 GitLab中文社区版补丁包安装3.5 修改GitLab配置文件/etc/gitlab/gitlab.rb3.6 在宿主机输入 http://192.168.200.26:88 地址就可以访问了…

Dom-clobbering原理和例题

目录 引入 1.获取标签 2.覆盖 3.多层覆盖 利用Dom-clobbering 1.tostring 2.集合取值 3.层级关系取值 4.三层取值 5.自定义属性 例题 1 2. 3. 引入 分析 引入 先用三个小例子看看dom-clobbering干了什么 1.获取标签 这个例子给img标签分别做了一个id和一个name…

热释电矢量传感器设计

1 概述 使用4个热释电传感器组成一个2X2的矩阵。通过曲线的相位差、 峰峰值等特征量来计算相关信息。本文使用STM32单片机设计、制作了热释电传感器矩阵&#xff1b;使用C#.NET设计了上位机软件。为以上研究做了试验平台。 2 硬件电路设计 2.1 热释电传感器介绍 热释电红外…

CCKS2023:基于企业数仓和大语言模型构建面向场景的智能应用

8月24日-27日&#xff0c;第十七届全国知识图谱与语义计算大会&#xff08;CCKS 2023&#xff09;在沈阳召开。大会以“知识图谱赋能通用AI”为主题&#xff0c;探讨知识图谱对通用AI技术的支撑能力&#xff0c;探索知识图谱在跨平台、跨领域等AI任务中的作用和应用途径。 作为…

MAC系统“无法验证开发者”问题

参考:https://blog.csdn.net/suxiang198/article/details/126550955 对于使用MAC电脑的同学而言&#xff0c;许多时候因为使用需要&#xff0c;从第三方源&#xff08;比如github等&#xff09;下载工具或软件&#xff0c;而在运行时会受到MAC系统的安全限制&#xff0c;老是弹…

【STM32】学习笔记-SPI通信

SPI通信 SPI通信&#xff08;Serial Peripheral Interface&#xff09;是一种同步的串行通信协议&#xff0c;用于在微控制器、传感器、存储器、数字信号处理器等之间进行通信。SPI通信协议需要使用4个线路进行通信&#xff1a;时钟线(SCLK)、主输入/主输出线(MISO)、主输出/主…