【框架学习 | 第二篇】暴打MyBatis-Plus——MyBatis的升级版本

教程来源链接:https://www.quanxiaoha.com/mybatis-plus/mybatis-plus-tutorial.html

教程作者:犬小哈

文章目录

  • 1.Mybatis Plus介绍
    • 1.1Mybatis和Mybatis Plus的区别是什么
      • 1.1.1什么是Mybatis?
      • 1.1.2区分Mybatis Plus和Mybatis
    • 1.2Mybatis Plus特点
    • 1.3支持的数据库
  • 2.环境搭建
    • 2.1前置条件——新建数据库表
    • 2.2Springboot整合Mybatis Plus
      • 2.2.1引入依赖
      • 2.2.2添加配置
      • 2.2.3配置类
    • 2.3添加实体类
    • 2.4添加Mapper/Dao类
      • 2.4.1解析BaseMapper类
  • 3.增删查改数据
    • 3.1新增数据
      • 3.1.1新增Service
      • 3.1.2注入WareService
    • 3.2删除数据
      • 3.2.1BaseMapper
      • 3.2.2ServiceImpl
    • 3.3查找数据
      • 3.3.1BaseMapper
        • (1)通过 Wrapper 组装查询条件
      • 3.3.2ServiceImpl
        • (1)get相关方法
        • (2)list相关方法
        • (3)page分页相关方法
        • (4)count查询记录总数
    • 3.4修改数据
      • 3.4.1BaseMapper
      • 3.4.2ServiceImpl
    • 3.5分页查询
      • 3.5.1添加分页插件
      • 3.5.2BaseMapper
      • 3.5.3举例
      • 3.5.4Page类说明
      • 3.5.5ServiceImpl
    • 3.6批量新增
      • 3.6.1 Mybatis Plus的伪批量插入
      • 3.6.2利用SQL注入器实现真批量插入
        • (1)创建SQL注入器 `InsertBatchSqlInjector`
        • (2)InsertBatchSomeColumn说明
        • (3)配置 SQL注入器
        • (4)新建MyBaseMapper
      • 3.6.3举例
  • 4.核心功能
    • 4.1常用注解
      • 4.1.1@TableName
      • 4.1.2@TableId
      • 4.1.3@IdType
      • 4.1.4@TableField
      • 4.1.5@TableLogic
    • 4.2Wrapper条件构造器
      • 4.2.1介绍
      • 4.2.2Wrapper继承关系
        • (1)AbstractWrapper
      • 4.2.常用方法
      • 4.2.1 allEq:多字段等于查询
      • 4.2.2 eq:单字段等于
      • 4.2.3 ne:不等于
      • 4.2.4 gt:大于
      • 4.2.5 ge:大于等于
      • 4.2.6 lt:小于
      • 4.2.7 le:小于等于
      • 4.2.8 between:之间
      • 4.2.9 notBetween:不在之间
      • 4.2.10 like:模糊查询
      • 4.2.11 nolike
      • 4.2.12 likeLeft
      • 4.2.13 likeRight
      • 4.2.14 isNull:为空
      • 4.2.15 isNotNull:非空
      • 4.2.16 in
      • 4.2.17 not in
      • 4.2.18 inSql:子查询
      • 4.2.19 notInSql
      • 4.2.20 group:分组
      • 4.2.21 orderByAsc:升序
      • 4.2.22 orderByDesc:降序
      • 4.2.23 orderBy:排序
      • 4.2.24 having
      • 4.2.25 or:拼接
      • 4.2.26 or:嵌套
      • 4.2.27 and:嵌套
      • 4.2.28 nested:正常嵌套:不带And 和 Or
    • 4.3Condition
      • 4.3.1问题
      • 4.3.2定义

在这里插入图片描述

1.Mybatis Plus介绍

1.1Mybatis和Mybatis Plus的区别是什么

1.1.1什么是Mybatis?

  1. MyBatis 是一款优秀的持久层框架,说白话就是一款操作数据库的框架。
  2. 它支持自定义 SQL、存储过程以及高级映射
  3. MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  4. MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1.1.2区分Mybatis Plus和Mybatis

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

1.2Mybatis Plus特点

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

1.3支持的数据库

  • MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb,informix,TDengine,redshift
  • 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库,优炫数据库

2.环境搭建

新建基于Maven的Springboot项目

2.1前置条件——新建数据库表

如图,新建fenge_wms数据库的wms_ware表

image-20240305192702507

2.2Springboot整合Mybatis Plus

2.2.1引入依赖

<!-- mybatis-plus 依赖 -->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version>
</dependency><!-- 单元测试依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency><!-- lombok 依赖 -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version>
</dependency><!-- mysql 依赖 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>

警告: 引入 MyBatis-Plus 之后请不要再次引入 MyBatis 以及 MyBatis-Spring,以避免因版本差异导致的问题。

2.2.2添加配置

  • application.yml:配置主机、用户、密码
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/fenge_wms?userUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 密码

2.2.3配置类

  • 新建MybatisPlusConfig配置类
@Configuration
@MapperScan("com.peng.mybatis.mapper")
public class MybatisPlusConfig {
}

@MapperScan 注解用于告诉 Mybatis Plus 框架需要扫描的 mapper 类的包路径,mapper 类主要用于操作数据库

2.3添加实体类

/*** * * @author peng* @email 3063272404@qq.com* @date 2024-01-17 16:05:14*/
@Data
@TableName("wms_ware")	//指定表名
public class WareEntity implements Serializable {private static final long serialVersionUID = 1L;/*** 仓库id*/@TableId(value="ware_id",type = IdType.AUTO)	//指定字段wareId为主键,并递增private Integer wareId;/*** 用户id*/private Integer userId;/*** 仓库名称*/private String name;/*** 仓库地点*/private String address;/*** 仓库面积【单位为平方米】*/private Integer area;/*** 纬度*/private BigDecimal latitude;/*** 经度*/private BigDecimal longitude;/*** 添加时间*/@TableField(fill = FieldFill.INSERT)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")private LocalDateTime addTime;/*** 修改时间*/@TableField(fill = FieldFill.UPDATE)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")private LocalDateTime updateTime;}

2.4添加Mapper/Dao类

/*** * * @author peng* @email 3063272404@qq.com* @date 2024-01-17 16:05:14*/
@Mapper
public interface WareDao extends BaseMapper<WareEntity> {}

2.4.1解析BaseMapper类

public interface BaseMapper<T> extends Mapper<T> {// 新增数据int insert(T entity);// 根据 ID 删除int deleteById(Serializable id);// 删除数据int deleteByMap(@Param("cm") Map<String, Object> columnMap);// 删除数据int delete(@Param("ew") Wrapper<T> queryWrapper);// 根据 ID 批量删除数据int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);// 根据 ID 更新int updateById(@Param("et") T entity);// 更新数据int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);// 根据 ID 查询T selectById(Serializable id);// 根据 ID 批量查询List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);// 查询数据List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);// 查询一条数据T selectOne(@Param("ew") Wrapper<T> queryWrapper);// 查询记录总数Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);// 查询多条数据List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);// 查询多条数据List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);// 查询多条数据List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);// 分页查询<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);// 分页查询<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}

3.增删查改数据

3.1新增数据

3.1.1新增Service

Mybatis Plus 同样也封装了通用的 Service 层 CRUD 操作,并且提供了更丰富的方法。

  • 定义WareService接口——继承IService
/*** ** @author peng* @email 3063272404@qq.com* @date 2024-01-17 16:05:14*/
public interface WareService extends IService<WareEntity> {PageUtils queryPage(Map<String, Object> params);}
  • 实现类——继承ServiceImpl<UserMapper,User>,并实现WareService
@Slf4j
@Service("wareService")
public class WareServiceImpl extends ServiceImpl<WareDao, WareEntity> implements WareService {@Overridepublic PageUtils queryPage(Map<String, Object> params) {IPage<WareEntity> page = this.page(new Query<WareEntity>().getPage(params),new QueryWrapper<WareEntity>());return new PageUtils(page);}
}

3.1.2注入WareService

@Autowired
private WareService wareService;

与 Mapper 层不同的是,Service 层的新增方法均以 save 开头,并且功能更丰富,来看看都提供了哪些方法:

image-20240305194332152

// 新增数据
sava(T) : boolean// 伪批量插入:实际上是通过 for 循环一条一条的插入
savaBatch(Collection<T>) : boolean// 伪批量插入,int 表示批量提交数,默认为 1000,实质还是for循环一条一条的插入
savaBatch(Collection<T>, int) : boolean// 新增或更新(单条数据):数据库中不存在该数据时,就执行插入操作:数据库中已存在时,就执行更新操作
saveOrUpdate(T) : boolean// 批量新增或更新
saveOrUpdateBatch(Collection<T>) : boolean// 批量新增或更新(可指定批量提交数)
saveOrUpdateBatch(Collection<T>, int) : boolean

3.2删除数据

3.2.1BaseMapper

查看BaseMapper封装的删除方法:

// 根据主键 ID 删除 (直接传入 ID)
int deleteById(Serializable id);// 根据主键 ID 删除 (传入实体类)
int deleteById(T entity);// 根据主键 ID 批量删除
int deleteBatchIds(Collection<?> idList)// 通过 Wrapper 条件构造器删除
int delete(Wrapper<T> queryWrapper);// 通过 Map 设置条件来删除
int deleteByMap(Map<String, Object> columnMap);

3.2.2ServiceImpl

查看ServiceImpl封装的删除方法:

image-20240305195648455

// 根据 entity 条件,删除记录
boolean remove(Wrapper<T> queryWrapper);// 根据 ID 删除
boolean removeById(Serializable id);// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);

3.3查找数据

3.3.1BaseMapper

  • 查看BaseMapper封装的查找方法:
// 根据 ID 查询
T selectById(Serializable id);// 通过 Wrapper 组装查询条件,查询一条记录
T selectOne(Wrapper<T> queryWrapper);// 查询(根据ID 批量查询)
List<T> selectBatchIds(Collection<? extends Serializable> idList);// 通过 Wrapper 组装查询条件,查询全部记录
List<T> selectList(Wrapper<T> queryWrapper);// 查询(根据 columnMap 来设置条件)
List<T> selectByMap(Map<String, Object> columnMap);// 根据 Wrapper 组装查询条件,查询全部记录,并以 map 的形式返回
List<Map<String, Object>> selectMaps(Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(Wrapper<T> queryWrapper);// =========================== 分页相关 ===========================
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(Wrapper<T> queryWrapper);
类型参数名描述
Serializableid主键 ID
Wrapper<T>queryWrapper实体对象封装操作类(可以为 null)
Collection<? extends Serializable>idList主键 ID 列表(不能为 null 以及 empty)
Map<String, Object>columnMap表字段 map 对象
IPage<T>page分页查询条件(可以为 RowBounds.DEFAULT)
(1)通过 Wrapper 组装查询条件
// eq()方法相当于 where user_id=1,可以加多个
// set()方法相当于 set xxx=xxx
new QueryWrapper().select("user_id","name").eq("user_id",1)		

3.3.2ServiceImpl

Service 层封装的查询方法注意分为 4 块:

  • getXXX : get 开头的方法
  • listXXX : list 开头的方法,用于查询多条数据;
  • pageXXX : page 开头的方法,用于分页查询;
  • count : 用于查询总记录数
(1)get相关方法

get 开头的相关方法用于 查询一条记录,方法如下:

// 根据 ID 查询
T getById(Serializable id);// 根据 Wrapper,查询一条记录。如果结果集是多个会抛出异常
T getOne(Wrapper<T> queryWrapper);// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);// 根据 Wrapper,查询一条记录,以 map 的形式返回数据
Map<String, Object> getMap(Wrapper<T> queryWrapper);// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

参数说明:

类型参数名描述
Serializableid主键 ID
Wrapper<T>queryWrapper实体对象封装操作类 QueryWrapper
booleanthrowEx有多个 result 是否抛出异常
Tentity实体对象
Function<? super Object, V>mapper转换函数
(2)list相关方法

list 开头的相关方法用于查询多条记录,方法如下:

// 查询所有
List<T> list();// 查询列表
List<T> list(Wrapper<T> queryWrapper);// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);// 查询所有列表, 以 map 的形式返回
List<Map<String, Object>> listMaps();// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);// 查询全部记录
List<Object> listObjs();// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

参数说明:

类型参数名描述
Wrapper<T>queryWrapper实体对象封装操作类 QueryWrapper
Collection<? extends Serializable>idList主键 ID 列表
Map<String, Object>columnMap表字段 map 对象
Function<? super Object, V>mapper转换函数
(3)page分页相关方法

后面单独讲

(4)count查询记录总数
// 查询总记录数(不带查询条件)
count();
// 查询总记录数(可以带查询条件)
count(Wrapper<T>)

3.4修改数据

3.4.1BaseMapper

  • 查看BaseMapper封装的查找方法:
//根据主键 ID 来更新
int updateById(T entity);//entity 用于设置更新的数据,wrapper 用于组装更新条件
int update(T entity, Wrapper<T> updateWrapper);

3.4.2ServiceImpl

Service 层封装的查询方法:

// 根据 ID 来更新,entity 用于设置 ID 以及其他更新条件
boolean updateById(T entity);// wrapper 用于设置更新数据以及条件
boolean update(Wrapper<T> updateWrapper);// entity 用于设置更新的数据,wrapper 用于组装更新条件
boolean update(T entity, Wrapper<T> updateWrapper);// 批量更新
boolean updateBatchById(Collection<T> entityList);// 批量更新,可手动设置批量提交阀值
boolean updateBatchById(Collection<T> entityList, int batchSize);// 保存或者更新
boolean saveOrUpdate(T entity);

3.5分页查询

3.5.1添加分页插件

@Configuration
public class MybatisPlusConfig {/*** 分页插件* @return*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor());return interceptor;}}

3.5.2BaseMapper

  • BaseMapper提供的分页查询方法
// 分页查询,page 用于设置需要查询的页数,以及每页展示数据量,wrapper 用于组装查询条件
IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper);// 同上,区别是用 map 来接受查询的数据
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, Wrapper<T> queryWrapper);
  • 参数说明:
类型参数名描述
Wrapper<T>queryWrapper实体对象封装操作类(可以为 null
IPage<T>page分页查询条件(可以为 RowBounds.DEFAULT

3.5.3举例

// 组装查询条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// where age = 30
queryWrapper.eq("age", 30);// 查询第 2 页数据,每页 10 条
Page<User> page = new Page<>(2, 10);page = userMapper.selectPage(page, queryWrapper);
System.out.println("总记录数:" + page.getTotal());
System.out.println("总共多少页:" + page.getPages());
System.out.println("当前页码:" + page.getCurrent());
// 当前页数据
List<User> users = page.getRecords();

执行上面的代码,实际上执行了两条 SQL : 先执行 COUNT(*) 查询出记录总数,然后才是分页语句 LIMIT:

image-20240305225802822

3.5.4Page类说明

该类继承了 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

3.5.5ServiceImpl

// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);

3.6批量新增

3.6.1 Mybatis Plus的伪批量插入

Mybatis Plus 内部封装的批量插入 savaBatch() 是个假的批量插入

List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {User user = new User();user.setName("犬小哈" + i);user.setAge(i);user.setGender(1);users.add(user);
}
// 批量插入
boolean isSuccess = userService.saveBatch(users);
System.out.println("isSuccess:" + isSuccess);

通过打印实际执行 SQL , 我们发现还是一条一条的执行 INSERT

image-20240306091459515

3.6.2利用SQL注入器实现真批量插入

(1)创建SQL注入器 InsertBatchSqlInjector
public class InsertBatchSqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {// super.getMethodList() 保留 Mybatis Plus 自带的方法List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);// 添加自定义方法:批量插入,方法名为 insertBatchSomeColumnmethodList.add(new InsertBatchSomeColumn());return methodList;}
}
(2)InsertBatchSomeColumn说明

InsertBatchSomeColumn 是 Mybatis Plus 内部提供的默认批量插入,只不过这个方法作者只在 MySQL 数据测试过,所以没有将它作为通用方法供外部调用,注意看注释:

(3)配置 SQL注入器
@Configuration
public class MybatisPlusConfig {/*** 自定义批量插入 SQL 注入器*/@Beanpublic InsertBatchSqlInjector insertBatchSqlInjector() {return new InsertBatchSqlInjector();}}
(4)新建MyBaseMapper

创建 MyBaseMapper 接口,让其继承自 Mybatis Plus 提供的 BaseMapper, 并定义批量插入方法

public interface MyBaseMapper<T> extends BaseMapper<T> {// 批量插入int insertBatchSomeColumn(@Param("list") List<T> batchList);}

注意:方法名必须为 insertBatchSomeColumn, 和 InsertBatchSomeColumn 内部定义好的方法名保持一致。

3.6.3举例

  • UseMapper
public interface UserMapper extends MyBaseMapper<User> {
}
  • 测试:
@Autowired
private UserMapper userMapper;@Test
void testInsertBatch() {List<User> users = new ArrayList<>();for (int i = 0; i < 3; i++) {User user = new User();user.setName("犬小哈" + i);user.setAge(i);user.setGender(1);users.add(user);}userMapper.insertBatchSomeColumn(users);
}

image-20240306092105537

4.核心功能

4.1常用注解

Mybatis Plus中常用注解有:

  1. @TableName:表名注解,标识实体类对应的表
  2. @TableId:主键注解
  3. @IdType:指定主键ID类型
  4. @TableField:指定数据库字段注解(非主键)。
  5. @TableLogic:逻辑删除注释
  6. @Version:乐观锁

4.1.1@TableName

  1. 作用:表名注解,标识实体类对应的表
  2. 不用添加该注解的两种方式:
    • 当表名和实体类的命名一致时,如表名 user , 实体类为 User 时,可不用添加 @TableName 注解
    • 通过全局配置声明表明前缀(以下例子演示数据库表均为wms_开头)
mybatis-plus:     global-config:db-config:table-prefix: wms_

4.1.2@TableId

  1. 作用:主键注解

  2. 举例

    image-20240305231304361

4.1.3@IdType

  1. 作用:指定主键ID类型

  2. 各种值情况:

    描述
    AUTO数据库 ID 自增
    NONE未设置主键类型(默认)
    INPUT插入数据前,需自行设置主键的值
    ASSIGN_ID分配 ID(主键类型为 Number(LongInteger)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
    ASSIGN_UUID分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID (默认 default 方法)
    ID_WORKER分布式全局唯一 ID 长整型类型 (推荐使用 ASSIGN_ID)
    UUID32 位 UUID 字符串 (推荐使用 ASSIGN_UUID)
    ID_WORKER_STR分布式全局唯一 ID 字符串类型 (推荐使用 ASSIGN_ID)

4.1.4@TableField

  1. 作用:指定数据库字段注解(非主键)

  2. 举例

    image-20240305231634643

4.1.5@TableLogic

  1. 作用:逻辑删除

  2. 举例

    image-20240305231717026

4.2Wrapper条件构造器

4.2.1介绍

  1. 在 Mybatis Plus 中,利用条件构造器 Wrapper 可以帮助我们组装各种 where 条件,具体实现类如 QueryWrapperUpdateWrapper 等,在查询、更新、删除操作中会被频繁用到。

4.2.2Wrapper继承关系

Wrapper 是个抽象类,先看下它的继承关系图:

image-20240305232146554

解释各个子类作用:

Wrapper  条件构造抽象类-- AbstractWrapper 查询条件封装,用于生成 sql 中的 where 语句。-- QueryWrapper Entity 条件封装操作类,用于查询。-- UpdateWrapper Update 条件封装操作类,用于更新。-- AbstractLambdaWrapper 使用 Lambda 表达式封装 wrapper-- LambdaQueryWrapper 使用 Lambda 语法封装条件,用于查询。-- LambdaUpdateWrapper 使用 Lambda 语法封装条件,用于更新。-- AbstractChainWrapper 链式查询条件封装 -- UpdateChainWrapper 链式条件封装操作类,用于更新。-- LambdaQueryChainWrapper 使用 Lambda 语法封装条件,支持链式调用,用于查询-- LambdaUpdateChainWrapper 使用 Lambda 语法封装条件,支持链式调用,用于更新-- QueryChainWrapper 链式条件封装操作类,用于查询。

ps:Kt 开头的类是使用 Kotlin 语言编写,咱是 Java,不用管。

(1)AbstractWrapper
  1. AbstractWrapper是QueryWrapper (LambdaQueryWrapper) 和 UpdateWrapper (LambdaUpdateWrapper) 的父类
  2. 用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件

4.2.常用方法

4.2.1 allEq:多字段等于查询

全部自动等于判断,或者个别自动非空判断:

// params : key 为数据库字段名, value 为字段值
allEq(Map<R, V> params)
// null2IsNull : 为 true 则在 map 的 value 为 null 时调用 isNull 方法,为 false 时则忽略 value 为null的
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
  • 代码示例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 = '老王'
// filter : 过滤函数,是否允许字段传入比对条件中
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) 
  • 代码示例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 = '老王'

4.2.2 eq:单字段等于

eq(R column, Object val)
eq(boolean condition, R column, Object val)
  • 代码示例: eq("name", "老王")相当于条件name = '老王'

4.2.3 ne:不等于

ne(R column, Object val)
ne(boolean condition, R column, Object val)

代码示例:ne("name", "老王")相当于条件name <> '老王'

4.2.4 gt:大于

gt(R column, Object val)
gt(boolean condition, R column, Object val)

代码示例: ge("age", 18)相当于条件age >= 18

4.2.5 ge:大于等于

ge(R column, Object val)
ge(boolean condition, R column, Object val)

4.2.6 lt:小于

lt(R column, Object val)
lt(boolean condition, R column, Object val)

4.2.7 le:小于等于

le(R column, Object val)
le(boolean condition, R column, Object val)

4.2.8 between:之间

between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)

4.2.9 notBetween:不在之间

notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)

4.2.10 like:模糊查询

like(R column, Object val)
like(boolean condition, R column, Object val)

作用:LIKE ‘%值%’

  • 例子:like(“name”, “王”)相当于条件name like ‘%王%’

4.2.11 nolike

notLike(R column, Object val)
notLike(boolean condition, R column, Object val)

4.2.12 likeLeft

likeLeft(R column, Object val)
likeLeft(boolean condition, R column, Object val)

作用:LIKE ‘%值’

例: likeLeft("name", "王")相当于条件name like '%王

4.2.13 likeRight

likeRight(R column, Object val)
likeRight(boolean condition, R column, Object val)

作用: LIKE ‘值%’

例: likeRight("name", "王")相当于条件name like '王%

4.2.14 isNull:为空

isNull(R column)
isNull(boolean condition, R column)

4.2.15 isNotNull:非空

isNotNull(R column)
isNotNull(boolean condition, R column)

4.2.16 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)

4.2.17 not in

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)

4.2.18 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)

4.2.19 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)

4.2.20 group:分组

groupBy(R... columns)
groupBy(boolean condition, R... columns)

说明:分组 GROUP BY 字段。

  • 例: groupBy("id", "name")相当于条件group by id,name,

4.2.21 orderByAsc:升序

orderByAsc(R... columns)
orderByAsc(boolean condition, R... columns)

说明:升序排序:ORDER BY 字段, … ASC

  • 例: orderByAsc("id", "name")相当于条件order by id ASC,name ASC

4.2.22 orderByDesc:降序

orderByDesc(R... columns)
orderByDesc(boolean condition, R... columns)

说明:降序排序:ORDER BY 字段, … DESC

  • 例: orderByDesc("id", "name")相当于条件order by id DESC,name DESC

4.2.23 orderBy:排序

orderBy(boolean condition, boolean isAsc, R... columns)

说明:排序:ORDER BY 字段, …

  • 例: orderBy(true, true, "id", "name")相当于条件order by id ASC,name ASC

4.2.24 having

作用:HAVING ( sql语句 )

having(String sqlHaving, Object... params)
having(boolean condition, String sqlHaving, Object... params)
  • 例: having("sum(age) > 10")相当于条件having sum(age) > 10
  • 例: having("sum(age) > {0}", 11)相当于条件having sum(age) > 11

4.2.25 or:拼接

or()
or(boolean condition)

例: eq("id",1).or().eq("name","老王")相当于条件id = 1 or name = '老王'

4.2.26 or:嵌套

例: or(i -> i.eq("name", "李白").ne("status", "活着"))相当于条件or (name = '李白' and status <> '活着')

4.2.27 and:嵌套

and(Consumer<Param> consumer)
and(boolean condition, Consumer<Param> consumer)

例: and(i -> i.eq("name", "李白").ne("status", "活着"))相当于条件and (name = '李白' and status <> '活着')

4.2.28 nested:正常嵌套:不带And 和 Or

nested(Consumer<Param> consumer)
nested(boolean condition, Consumer<Param> consumer)
  • 例: nested(i -> i.eq("name", "李白").ne("status", "活着"))相当于条件(name = '李白' and status <> '活着')

4.3Condition

4.3.1问题

image-20240306091013502

4.3.2定义

布尔类型的 condition 顾名思义就是条件判断。举个栗子,实际项目中,如果是一个查询分页数据的页面,用户通常可以手动选择多个条件进行查询,那么后台的代码实现上,Wrapper 条件就是动态组装的,需要对每一个可能会出现的条件进行判断,伪代码大致如下:

if (字段1 != null) {wrapper.eq("name", "犬小哈")
}if (字段2 != null) {wrapper.ge("age", 20)
}// ...省略

如何 if 判断只有几个还好,一旦给你来 10 个,你就会发现代码又臭又长,于是救世主 condition 出现了,它可以帮助我们省略冗长的 if 代码,让动态组装的判断更加优雅。

举个示例,假设分页接口中,前端可能传过来的动态条件字段为姓名,年龄(范围类型),那么可以通过 condition 可以如下实现:

@Test
void testCondition() {// 模拟前端传过来的数据String name = "犬小哈";// 年龄大于等于 20 且小于等于 30 的用户Integer ageStart = 20;Integer ageEnd = 30;QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq(StringUtils.isNotBlank(name), "name", name).ge(ageStart != null, "age", ageStart).le(ageEnd != null, "name", ageEnd);List<User> users = userMapper.selectList(wrapper);
}
  • lambda格式:
@Test
void testCondition() {// 模拟前端传过来的数据String name = "犬小哈";// 年龄大于等于 20 且小于等于 30 的用户Integer ageStart = 20;Integer ageEnd = 30;LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(StringUtils.isNotBlank(name), User::getName, name).ge(ageStart != null, User::getAge, ageStart).le(ageEnd != null, User::getAge, ageEnd);List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);
}
  • 得出SQL语句:

image-20240306091231206

功能正常,相比较上面需要写一堆 if 判断,我们可以直接将判断条件传给 condition 参数,代码看上去舒服多了

在这里插入图片描述

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

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

相关文章

Vue3_2024_6天【回顾上篇watch常见的前三种场景】另两种待补

第一种情况&#xff1a;监视【ref】定义&#xff08;基本数据类型&#xff09; 1.引入watch2.格式&#xff1a;watch&#xff08;基本数据类型数据&#xff0c;监视变化的回调函数&#xff09; 注意点&#xff1a; 2.1.watch里面第一个参数&#xff0c;是数据~~【监视的基本类…

泛型 --java学习笔记

什么是泛型 定义类、接口、方法时&#xff0c;同时声明了一个或者多个类型变量&#xff08;如&#xff1a;<E>&#xff09;&#xff0c;称为泛型类、泛型接口&#xff0c;泛型方法、它们统称为泛型 可以理解为扑克牌中的癞子&#xff0c;给它什么类型它就是什么类型 如…

开篇语 | 容器中的⼤模型 (LLM in Containers)

如果我们想搭建一个企业级的大模型应用&#xff0c;不管使用开源的基础模型自己来发布&#xff0c;还是使用类似于 ChatGPT 的闭源 API&#xff0c;我们都需要搭建一个大模型流水线来管理应用体系中除了基础模型之外的功能模块。 Replit 的一篇博客&#xff08;https://blog.r…

鸿蒙ArkTS语言快速入门-TS(一)

ArkTS与TS的学习 ArkTS与TS的关系简述TypeScript&#xff08;TS&#xff09;简述基础类型1&#xff0c;let2&#xff0c;const3&#xff0c;布尔类型4&#xff0c;数字number5&#xff0c;字符串string6&#xff0c;数组Array7&#xff0c;元组 Tuple8&#xff0c;枚举 enum9&a…

腾讯云服务器和阿里云服务器哪家更优惠?2024价格对比

2024年阿里云服务器和腾讯云服务器价格战已经打响&#xff0c;阿里云服务器优惠61元一年起&#xff0c;腾讯云服务器61元一年&#xff0c;2核2G3M、2核4G、4核8G、4核16G、8核16G、16核32G、16核64G等配置价格对比&#xff0c;阿腾云atengyun.com整理阿里云和腾讯云服务器详细配…

【Web前端入门学习】—CSS

目录 CSS简介CSS语法CSS三种导入方式CSS选择器元素选择器&#xff08;标签选择器&#xff09;类选择器ID选择器通用选择器子元素选择器后代选择器&#xff08;包含选择器&#xff09;并集选择器&#xff08;兄弟选择器&#xff09;伪类选择器伪元素选择器 CSS常用属性盒子模型网…

练习 6 Web [极客大挑战 2019]HardSQL

[极客大挑战 2019]HardSQL 先尝试登录&#xff0c;查看报错信息 admin 111 password 1111 登录失败admin 111 password 1’or’1 登录成功 这里直接试了万能密码成功&#xff0c;复习一下&#xff0c;第一个 ’ 是为了闭合前面的sql语句&#xff0c;最后的1后面没有 ’ 是因为…

【鸿蒙 HarmonyOS 4.0】解决:搜索无效问题

一、背景 页面包含搜索框和列表&#xff0c;列表默认展示所有数据并具有分页功能。然而&#xff0c;在输入关键字到搜索框时&#xff0c;列表未正确展示搜索结果。 二、功能实现 2.1、原代码及实现效果 import ChargeType from ../../viewModel/ChargeType import ChargeMo…

手写分布式配置中心(三)增加实时刷新功能(短轮询)

要实现配置自动实时刷新&#xff0c;需要改造之前的代码。代码在https://gitee.com/summer-cat001/config-center​​​​​​​ 服务端改造 服务端增加一个版本号version&#xff0c;新增配置的时候为1&#xff0c;每次更新配置就加1。 Overridepublic long insertConfigDO(…

【Python刷题】环形链表

问题描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&a…

[数据结构]OJ用队列实现栈

225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; 官方题解&#xff1a;https://leetcode.cn/problems/implement-stack-using-queues/solutions/432204/yong-dui-lie-shi-xian-zhan-by-leetcode-solution/ 首先我们要知道 栈是一种后进先出的数据结构&#xff0c…

【大模型】Hugging Face下载大模型的相关文件说明

Hugging Face下载大模型文件说明 1.前言 ​ 上图是毛毛张在HuggingFace的官网上的ChatGLM-6B大模型的所有文件,对于初学者来说,对于上面的文件是干什么的很多小伙伴是很迷糊的,根本不知道是干什么的,毛毛张接下来将简单讲述一下上面的每个文件的作用。 2.文件说明 在Hug…