MyBatisPlus - 润物无声、效率至上、丰富功能

目录

一、简介 

1.1、为什么要使用 MybatisPlus

二、使用指南

2.1、依赖

2.2、配置

2.3、常用注解

2.4、BaseMapper 的使用

2.4.1、定义 Mapper 接口

2.4.2、基于 QueryWrapper 的查询(不推荐)

2.4.3、基于 UpdateWrapper 的修改(不推荐)

2.4.4、基于 Lambda 的查询、修改(推荐)

2.5、自定义 SQL

2.6、IService 和 ServiceImpl

2.7、Db 静态工具

2.8、分页插件

2.8.1、配置类

2.8.2、实际使用


一、简介 


1.1、为什么要使用 MybatisPlus

a)润物无声:

在 MyBatis 基础上只做增强,不做修改,不会对现有工程产生影响,并且在启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作.

b)效率至上:

MP 提供了很多现成的单表操作,只需简单配置,就可以进行单表的 CRUD,节省大量时间.  另外还提供了 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错.

c)扩展功能:

代码生成、自动分页、逻辑删除、自动填充等等.... 但是我觉得这里有些东西可能自己基建更合适.

二、使用指南


2.1、依赖

MyBatisPlus 的 starter 可以直接替代 MyBatis 的 starter

        <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency>

2.2、配置

mybatis-plus:type-aliases-package: com/cyk/mp/model/domain # 别名扫描包# 以下配置都是默认值,可以根据项目情况进行修改mapper-locations: "classpath*:/mapper/**/*.xml"  # Mapper.xml 文件地址configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印 sqlmap-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射cache-enabled: false # 是否开启二级缓存global-config:db-config:id-type: assign_id # 默认雪花算法,另外还有 auto(自增id) assign_uuid(uuid)update-strategy: not_null # 更新策略: 只更新非空字段

2.3、常用注解

a)常用注解如下:

  • @TableName:用来指定表名.
  • @TableId:用来指定表中的主键字段信息.
  • @TableField:用来指定表中的普通字段信息.

具体的注解参数可以参考官网:注解 | MyBatis-Plus

例如 user_info 表如下:

类定义如下:

@Data
@TableName(value = "user_info", autoResultMap = true)
public class User {@TableId(value = "id", type = IdType.AUTO) //value 默认是 id, type 默认是雪花算法,这里修改为自增长private Long id;@TableField("username")private String name;@TableField("is_married")private Boolean isMarried;private Integer age;//这里会自动驼峰转下划线private Date ctTime;private Date utTime;}

Ps:此案例贯穿全文 

b)注意事项如下

@TableField 中若指定 value 生效的前提是: @TableName 中 autoResultMap = true,此设置会按照 TableField 中的设置的 value 自动生成 resultMap.

IdType 枚举类型如下

  • AUTO:数据库 ID 自增.
  • NONE:无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
  • INPUT:通过 set 方法自行注入.
  • ASSIGN_ID:分配 ID(主键类型为 Number(Long 和 Integer)或 String),接口 IdentifierGenerator 的方法 nextid 来生成 id,默认是雪花算法.
  • ASSIGN_UUID:分配 UUID,主键类型为 String

使用 @TableASSIGN_UUIDField 的常见场景:

  • 成员变量与数据库字段名不一致
  • 成员变量名以 is 开头,且是布尔值.
  • 成员变量名与数据库关键字冲突(反引号解决)
  • 成员变量不是数据库字段(@TableField(exist = false) 表示表中不存在该字段,用来排除).

2.4、BaseMapper<T> 的使用

2.4.1、定义 Mapper 接口

自定义的 Mapper 类继承 MyBatisPlus 提供的 BaseMapper 接口:

例如对 User 类操作.

public interface UserMapper extends BaseMapper<User> {}

可以看到 BaseMapper 接口中提供了很多方法,都可以直接调用~

2.4.2、基于 QueryWrapper 的查询(不推荐)

QueryWrapper 通常用来构建 select、delete 的 select 和 where 条件部分,以及 update 的 where 部分.

a)案例一:查询出 name 中带 y 的,age 小于 30 的( id、username、age、is_married )信息.

MP 实现如下:

    @Testpublic void test1() {//1.构造查询条件(支持链式编程)QueryWrapper<User> wrapper = new QueryWrapper<User>().select("id", "username", "age", "is_married").like("username", "y").lt("age", 30); // ge大于等于 gt大于 lt小于 le小于等于//2.查询List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);}

MP 实际生成的 SQL 语句如下:

SELECT id,username,age,is_married FROM user_info WHERE (username LIKE ? AND age < ?)

b)案例二:更新 username 为 cyk 的 is_married 字段为 true.

MP 实现如下:

    @Testpublic void test2() {//1.要更新的数据User user = new User();user.setIsMarried(true);//2.构造更新条件QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "cyk");//3.执行更新userMapper.update(user, wrapper);}

MP 实际生成的 SQL 语句如下:

UPDATE user_info SET is_married=? WHERE (username = ?)

2.4.3、基于 UpdateWrapper 的修改(不推荐)

UpdateWrapper 通常用来构造 update 语句的 set 和 where 部分.

a)案例一:让 id 为 1,2,3 的用户的 age 加 10.

MP 实现如下:

    @Testpublic void test3() {List<Long> ids = List.of(1L,2L,3L);UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("age = age + 10").in("id", ids);userMapper.update(null, wrapper);}

MP 实际生成的 SQL 语句如下: 

 UPDATE user_info SET age = age + 10 WHERE (id IN (?,?,?))

2.4.4、基于 Lambda 的查询、修改(推荐)

上面提到的这两种方式实际上是硬编码的写法(不推荐),下面讲的 Lambda 写法才是最合适的.

a)案例一:查询出 name 中带 y 的,age 小于 30 的( id、username、age、is_married )信息.

MP 实现如下:

    @Testpublic void test4() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().select(User::getId, User::getName, User::getAge, User::getIsMarried).lt(User::getAge, 30);List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);}

MP 底层执行的 sql 如下: 

SELECT id,username,age,is_married FROM user_info WHERE (age < ?)

 b)案例二:在公司经常会遇到一个接口复用多个接口的情况,例如根据 ids、name、is_married 查询用户信息,但是这三个参数都有可能为空.  这里 MP 能很好的抛弃 if 语句,十分优雅

    @Testpublic void test6() {//1.假设前端传入请求数据UserDTO dto = new UserDTO();dto.setIds(List.of(1L,2L,3L));dto.setName(null);dto.setAgeLeft(10);dto.setAgeRight(30);//2.构造请求LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().in(!dto.getIds().isEmpty(), User::getId, dto.getIds()).eq(StringUtils.isNotBlank(dto.getName()), User::getName, dto.getName()).between(dto.getAgeLeft() != null && dto.getAgeRight() != null,User::getAge, dto.getAgeLeft(), dto.getAgeRight());//3.执行查询List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);}

 MP 底层执行的 sql 如下: 

SELECT id,username,is_married,age,ct_time,ut_time FROM user_info WHERE (id IN (?,?,?) AND age BETWEEN ? AND ?)

2.5、自定义 SQL

MyBatisPlus 更适合于构建复杂的 where 的条件(避免使用一些 动态 sql 显得臃肿),对于例如 update 中出现例如 "set age = age + 10" 这样的语句就只能使用硬编码.

而 MyBatisPlus 是包含 MyBatis 的,因此可以通过 MyBatis 定义 sql 语句中剩下的部分.

总而言之:对于复杂 update 语句,自定义 where 条件之前的语句,MP 构建 where 条件之后的语句

案例:让 id 为 1,2,3 的用户的 age 加 10.

a)基于 Wrapper 构建 where 条件

        //让 age 增加 10int addAge = 10;//要修改哪些用户List<Long> ids = List.of(1L, 2L, 3L);LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().in(User::getId, ids);//updateBatchByIds 是自定义的方法userMapper.updateBatchByIds(wrapper, addAge);

b)在 mapper 方法参数中用 Param 注解声明 wrapper 变量名称,必须是 ew 

@Mapper
public interface UserMapper extends BaseMapper<User> {//wrapper 的变量声明必须是 ewvoid updateBatchByIds(@Param("ew") LambdaQueryWrapper<User> wrapper,@Param("addAge") int addAge);}

如果忘记是 ew 这个东西,也可以通过 Constants 这个常量来找到.

 

c)在 xml 文件中自定义 sql,并使用 Wrapper 条件

    <update id="updateBatchByIds">update user_infoset age = age + #{addAge} ${ew.customSqlSegment}</update>

MP 实际生成 sql 语句如下:

 update user_info set age = age + ? WHERE (id IN (?,?,?))

2.6、IService 和 ServiceImpl

Ps:不太建议在 Service 层乱造,可以自己封装以下... 当然 BaseMapper 也够用.

IService 接口提供中也提供了很多的 方法,并在 ServiceImpl 也给出了具体的实现.

这里的方法和上面讲到的 BaseMapper 大差不差,就不展开讲了.

下面以 User 类为例.

a)首先自定义 mapper 接口,继承 BaseMapper

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

a)我们只需要在我们自定义的 IXXXService 上继承 IService

public interface IUserService extends IService<User> {}

b)并在自定义的 XXXServiceImpl 上继承 ServiceImpl 即可

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {}

d)之后这些方法都可以随便用了,例如 getById

    @Overridepublic void xxxMethod(Long id) {User byId = getById(id);//...}

e)当然,这里也提供了对应的 lambda 表达式

    @Overridepublic List<User> query(QueryUserDTO dto) {return lambdaQuery().in(!dto.getIds().isEmpty(), User::getId, dto.getIds()).eq(StringUtils.hasLength(dto.getName()), User::getName, dto.getName()).between(dto.getMinAge() != null && dto.getMaxAge() != null,User::getAge, dto.getMinAge(), dto.getMaxAge()).list(); //生成一个 list    当然也可以选择生成 page 后面会讲}

模拟创建请求调用 query 方法如下:

        QueryUserDTO dto = QueryUserDTO.builder().ids(List.of(1L,2L,3L)).name(null).minAge(10).maxAge(30).build();List<User> users = userService.query(dto);users.forEach(System.out::println);

 MP 实际执行的 sql 语句

SELECT id,username,is_married,age,ct_time,ut_time FROM user_info WHERE (id IN (?,?,?) AND age BETWEEN ? AND ?)

2.7、Db 静态工具

可以看到和 IService 中方法几乎一摸一样,只不过 IService 接口里面的方法都是非静态 ,而 DB 这个静态工具里面的方法自然也都是静态的

而且可以看到一些细小的变化,他的方法除了新增和修改以外都需要指定泛型,这是因为他需要通过反射才能拿到实体类的字节码,才知道你的表信息.

那这玩意到底和 IService 有什么区别呢?

假设有两张表,用户表和地址表,并且业务需要根据用户 id 查询地址,又需要根据地址查询用户id,那么就你就可能去 UserService 中注入 AddressService ,而又在 AddressService 中注入 UserService,这样就产生了循环依赖问题.

虽然循环依赖在较新的 Spring 版本中已被解决,但是最好还是需要我们开发人员去注意这个问题,保证系统的稳定性.

此时就可以通过 DB 静态工具类来实现了. 

2.8、分页插件

2.8.1、配置类

首先,要在配置类种注册 MyBatisPlus 的核心插件,同时添加分页插件:

@Configuration
public class MybatisConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {//1.初始化核心插件MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//2.创建分页插件PaginationInnerInterceptor page = new PaginationInnerInterceptor(DbType.MYSQL);//设置分页上线page.setMaxLimit(100L);//3.添加分页插件到 MybatisPlusinterceptor.addInnerInterceptor(page);return interceptor;}}

Ps:缺少以上配置,就没法使用分页.  这个插件本质就是在执行指令之前被拦截器拦截下来, 添加分页命令.

2.8.2、实际使用

案例:在公司经常会遇到一个接口复用多个接口的情况,例如根据 ids、name、is_married 查询用户信息,但是这三个参数都有可能为空,最后的结果分页显示(limit 3 offset 0),并根据 id 升序排序.

Ps:在 Page 中若没有使用 addOrder 方法,或者方法参数为空,默认按照创建时间排序.

a)MP 实现如下:

        //1.默认请求PageUserDTO dto = PageUserDTO.builder().start(2).limit(1).ids(List.of(1L,2L,3L)).name(null).minAge(10).maxAge(30).build();//2.分页查询//2.1 构建查询LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().in(!dto.getIds().isEmpty(), User::getId, dto.getIds()).eq(StringUtils.isNotBlank(dto.getName()), User::getName, dto.getName()).between(dto.getMinAge() != null && dto.getMaxAge() != null, User::getAge, dto.getMinAge(), dto.getMaxAge());//2.2 构建分页Page<User> page = Page.of(dto.getStart(), dto.getLimit()); //起始页码(非下标), 每页显示条数page.addOrder(new OrderItem("id", true)); //true 表示升序//3.查询Page<User> result = userService.page(page, wrapper);//3.1 分页数据List<User> records = result.getRecords();//3.2 总条数long total = result.getTotal();//3.3 总页数long pages = result.getPages();

MP 底层执行的 sql 如下:

SELECT COUNT(*) AS total FROM user_info WHERE (id IN (?, ?, ?) AND age BETWEEN ? AND ?)SELECT id, username, is_married, age, ct_time, ut_time FROM user_info WHERE (id IN (?, ?, ?) AND age BETWEEN ? AND ?) ORDER BY id ASC LIMIT ?,?

 

b)但是实际开发一般也不会写的像上述代码一样这么麻烦,更多的可能是这样

        //1.默认请求PageUserDTO dto = PageUserDTO.builder().start(2).limit(1).ids(List.of(1L,2L,3L)).name(null).minAge(10).maxAge(30).build();//2.构建分页条件Page<User> page = Page.of(dto.getStart(), dto.getLimit()); //起始页码(非下标), 每页显示条数page.addOrder(new OrderItem("id", true)); //true 表示升序//3.查询Page<User> result = userService.lambdaQuery().in(!dto.getIds().isEmpty(), User::getId, dto.getIds()).eq(StringUtils.isNotBlank(dto.getName()), User::getName, dto.getName()).between(dto.getMinAge() != null && dto.getMaxAge() != null, User::getAge, dto.getMinAge(), dto.getMaxAge()).page(page);//3.1 分页数据List<User> records = result.getRecords();//3.2 总条数long total = result.getTotal();//3.3 总页数long pages = result.getPages();

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

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

相关文章

Sentinel 流控-链路模式

链路模式 A B C 三个服务 A 调用 C B 调用 C C 设置流控 ->链路模式 -> 入口资源是 A A、B 服务 package com.learning.springcloud.order.controller;import com.learning.springcloud.order.service.BaseService; import org.springframework.beans.factory.annotatio…

腾讯云4核8G服务器3年600元?

腾讯云4核8G服务器3年600元&#xff1f;目前的价格是轻量应用服务器4核8G12M带宽一年446元、646元15个月&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;标准型SA2服务器1444.8元一年&#xff0c;在txy.wiki可以查询详细…

Excel一键导入导出-EasyPOI

EasyPOI是一款优秀的开源Java库&#xff0c;专为简化和优化Excel文件的导入导出操作而设计。下面&#xff0c;我会介绍EasyPOI在项目中使用EasyPOI&#xff0c;实现Excel文件的高效操作。帮助读者全面了解和掌握这一工具。 EasyPOI简介 官网&#xff1a; http://www.wupaas.co…

串口通信知识点

串口的话主要就是用来进行通信的。 1>串行通信&#xff0c;并行通信。 串行通信&#xff1a;只使用一根线来进行数据发送或者是接收&#xff0c;串行通信传输数据是一位一位进行传输 并行通信&#xff1a;使用多跟线进行数据的发送和接收&#xff0c;并行通信可以一次传输…

windows服务启动

一.NetCore 1.创建启动脚本run_instal.bat,例如程序文件为ApiDoc.exe set serviceName"Apidoc Web 01" set serviceFilePath%~dp0ApiDoc.exe set serviceDescription"ApiDoc 动态接口服务 web 01"sc create %serviceName% BinPath%serviceFilePath% sc c…

如何在Django中使用分布式定时任务并结合消息队列

如何在Django中使用分布式定时任务并结合消息队列 如何在Django中使用分布式定时任务并结合消息队列项目背景与意义实现步骤1. 安装Celery和Django-celery-beat2. 配置Celery3. 配置Django-celery-beat4. 定义定时任务5. 启动Celery worker 和 beat6. Celery 指令7. 对接消息队…

SP1:基于Plonky3构建的zkVM

1. 引言 SP1为SuccictLab开源的&#xff0c;基于Plonky3构建的zkVM。 开源代码见&#xff1a; https://github.com/succinctlabs/sp1&#xff08;Rust&#xff09; 当前暂未实现onchain-verifier&#xff0c;但会采用标准的STARK->SNARK verifier。 SP1 zkVM基于的指令…

「软件设计师」操作系统基本原理

操作系统概述 操作系统与计算机体系结构之间的关系 操作系统具备的管理职能 进程管理 进程的状态前趋图pv操作死锁问题存储管理 段页式存储页面置换算法文件管理 索引文件位示图作业管理设备管理 数据传输控制方式微内核操作系统 虚设备与SPOOLING技术 进程管理 进程的状态…

数据库日志已经很大了,比如200多G,不能收缩到几兆,实际操作过只能到30G

当数据库日志文件&#xff08;通常称为事务日志或事务日志文件&#xff09;变得非常大时&#xff0c;确实可能会遇到问题&#xff0c;因为这会占用大量的磁盘空间&#xff0c;并可能影响数据库的性能。收缩日志文件到非常小的大小&#xff08;例如从200多G到几兆&#xff09;可…

UnityShader——02三大主流编程语言

三大主流编程语言 Shader Language Shader language的发展方向是设计出在便携性方面可以与C/JAVA相比的高级语言&#xff0c;“赋予程序员灵活而方便的编程方式”&#xff0c;并“利用图形硬件的并行性&#xff0c;提高算法的效率” Shader language目前主要有 3 种语言&…

Python OpenCV 入门 这篇就够了

目录 1.初步认识OpenCV 1.1OpenCv概述 1.2OpenCV模块 2.图像处理的基本操作 2.1 imread()方法读取图像 2.2 显示图像 2.2.1 imshow()方法显示图像 2.2.2 waitKey()方法设置按键事件 2.2.3 destroyAllWindows()方法销毁所有窗口 3.3 imwrite保存图像 3.4 获取图像属性…

springboot/ssm招投标系统Java在线招投标项目专家管理系统

springboot/ssm招投标系统Java在线招投标项目专家管理系统 开发语言&#xff1a;Java 框架&#xff1a;springboot&#xff08;可改ssm&#xff09; vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&am…

【OrangePi Zero2 智能家居】智能家居项目的软件实现

一、项目整体设计 二、项目代码的前期准备 三、实现语音监听接口 四、实现socket监听接口 五、实现烟雾报警监听接口 六、实现设备节点代码 七、实现接收消息处理接口 一、项目整体设计 整体的软件框架大致如下&#xff1a; 整个项目开启4个监听线程&#xff0c; 分别是&…

【洛谷 P3367】【模板】并查集 题解(并查集)

【模板】并查集 题目描述 如题&#xff0c;现在有一个并查集&#xff0c;你需要完成合并和查询操作。 输入格式 第一行包含两个整数 N , M N,M N,M ,表示共有 N N N 个元素和 M M M 个操作。 接下来 M M M 行&#xff0c;每行包含三个整数 Z i , X i , Y i Z_i,X_i,Y…

为什么有些人喜欢回答问题答非所问?为什么有些人的处事风格是热情、礼貌、一问三不知的人?

问题描述&#xff1a;为什么有些人喜欢回答问题答非所问&#xff1f;为什么有些人的处事风格是热情、礼貌、一问三不知的人&#xff1f; 问题解答&#xff1a; 有些人喜欢回答问题答非所问可能有几种原因&#xff1a; 缺乏知识或技能&#xff1a;有些人可能不了解问题的答案&…

奇异值分解(SVD)

对于一个方阵而言&#xff0c;采用的是特征分解&#xff0c;参考《矩阵特征值分解&#xff08;EVD&#xff09;-CSDN博客》

高程 | 数据的共享与保护(c++)

文章目录 &#x1f4da;标识符的作用域与可见性&#x1f407;作用域&#x1f407;可见性 &#x1f4da;对象的生存期&#x1f407;静态生存期&#x1f407;动态生存期 &#x1f4da;类的静态成员&#x1f407;静态数据成员&#x1f407;静态函数成员 &#x1f4da;类的友元&…

你的电脑关机吗

目录 程序员为什么不喜欢关电脑&#xff1f; 电脑长时间不关机会怎样? 电脑卡顿 中度风险 硬件损耗 能源浪费 散热问题 软件问题 网络安全问题 程序员为什么不喜欢关电脑&#xff1f; 大部分人都会选择将电脑进行关机操作。其实这不难理解&#xff0c;毕竟人类都需要…

MyBatis篇----第五篇

系列文章目录 文章目录 系列文章目录前言一、MyBatis 实现一对一有几种方式?具体怎么操作的?二、MyBatis 实现一对多有几种方式,怎么操作的?三、Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?四、Mybatis 的一级、二级缓存前言 前些天发现了一个巨牛的人工智能…

每日一题 KY11 二叉树遍历

编一个程序&#xff0c;读入用户输入的一串先序遍历字符串&#xff0c;根据此字符串建立一个二叉树&#xff08;以指针方式存储&#xff09;。 例如如下的先序遍历字符串&#xff1a; ABC##DE#G##F### 其中“#”表示的是空格&#xff0c;空格字符代表空树。建立起此二叉树以后&…