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

news2024/10/24 1:54:36

教程来源链接: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.Driver
        url: jdbc:mysql://127.0.0.1:3306/fenge_wms?userUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
        username: root
        password: 密码

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 {
    @Override
    public 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
     */
    @Bean
    public 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 {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
    	// super.getMethodList() 保留 Mybatis Plus 自带的方法
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        // 添加自定义方法:批量插入,方法名为 insertBatchSomeColumn
        methodList.add(new InsertBatchSomeColumn());
        return methodList;
    }
}
(2)InsertBatchSomeColumn说明

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

(3)配置 SQL注入器
@Configuration
public class MybatisPlusConfig {


    /**
     * 自定义批量插入 SQL 注入器
     */
    @Bean
    public 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.coloradmin.cn/o/1498092.html

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

相关文章

【C语言】终の指针(前篇)

个人主页点这里~ 指针初阶点这里~ 指针初阶2.0点这里~ 指针进阶点这里~ 终の指针 一、回调函数二、qsort函数1、整形比较2、结构数据比较①结构体②-> 的使用③结构数据比较 一、回调函数 回调函数就是⼀个通过函数指针调用的函数。 把一个函数的指针作为参数传递给另一…

勾股定理的七种经典证明

据说勾股定理约有500种证明方法&#xff0c;下面介绍几种经典的证明方法。 一、切割重拼法。 顾名思义&#xff0c;就是将图形切割成其他形式的图形&#xff0c;然后通过拼图转换为另一种图形&#xff0c;这个过程中图形的面积是不变的。 “赵爽弦图”是这种方法的经典应用&…

Mysql案例之GROUP_CONCAT函数详解

Hello&#xff0c;大家好&#xff0c;我是灰小猿&#xff0c;一个超会写bug的程序员&#xff01; 今天这篇文章记录一个最近开发中遇到的mysql实战场景&#xff0c;觉得还挺典型的&#xff0c;就在此做一下记录。 先看一下举例场景&#xff1a; mysql中学生表与学科表通过关…

Linux设备模型(九) - bus/device/device_driver/class

一&#xff0c;设备驱动模型 1&#xff0c;概述 在前面写的驱动中&#xff0c;我们发现编写驱动有个固定的模式只有往里面套代码就可以了&#xff0c;它们之间的大致流程可以总结如下&#xff1a; 实现入口函数xxx_init()和卸载函数xxx_exit() 申请设备号 register_chrdev_r…

首发:鸿蒙面试真题分享【独此一份】

最早在23年华为秋季发布会中&#xff0c;就已经宣布了“纯血鸿蒙”。而目前鸿蒙处于星河版中&#xff0c;加速了各大互联网厂商的合作。目前已经有200参与鸿蒙的原生应用开发当中。对此各大招聘网站上的鸿蒙开发需求&#xff0c;每日都在增长中。 2024大厂面试真题 目前的鸿蒙…

OpenHarmony教程指南—ArkUI中组件、通用、动画、全局方法的集合

介绍 本示例为ArkUI中组件、通用、动画、全局方法的集合。 本示例使用 Tabs容器组件搭建整体应用框架&#xff0c;每个 TabContent内容视图 使用 div容器组件 嵌套布局&#xff0c;在每个 div 中使用 循环渲染 加载此分类下分类导航数据&#xff0c;底部导航菜单使用 TabCont…

LeetCode 2917.找出数组中的 K-or 值:基础位运算

【LetMeFly】2917.找出数组中的 K-or 值&#xff1a;基础位运算 力扣题目链接&#xff1a;https://leetcode.cn/problems/find-the-k-or-of-an-array/ 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 nums 中的 K-or 是一个满足以下条件的非负整数&#xff1a; 只有…

如何合理布局子图--确定MATLAB的subplot子图位置参数

确定MATLAB的subplot子图位置参数 目录 确定MATLAB的subplot子图位置参数摘要1. 问题描述2. 计算过程2.1 确定子图的大小和间距2.2 计算合适的figure大小2.3 计算每个子图的position数据 3. MATLAB代码实现3.1 MATLAB代码3.2 绘图结果 4. 总结 摘要 在MATLAB中&#xff0c;使用…

网络编程套接字(1)—网络编程基础

目录 一、为什么需要网络编程? 二、什么是网络编程 三、网络编程中的基本概念 1、发送端和接收端 2、请求和响应 3、客户端和服务端 四、常见的客户端服务端模型 1、一问一答模型 2、一问多答模型 3、多问一答模型 4、多问多答模型 一、为什么需要网络编程? 为什么…

(二十二)从零开始搭建k8s集群——高可用kubernates集群搭建上篇

前言 本节内容分为上、中、下三篇&#xff0c;上篇主要是关于搭建k8s的基础环境&#xff0c;包括服务器基本环境的配置&#xff08;网络、端口、主机名、防火墙、交换分区、文件句柄数等&#xff09;、docker环境部署安装配置、镜像源配置等。中篇会介绍k8s的核心组件安装、k8…

rk3568 恢复出厂设置横屏

author daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 daisy.skye_嵌入式,Linux,Qt-CSDN博客daisy.skye擅长嵌入式,Linux,Qt,等方面的知识https://blog.csdn.net/qq_40715266?typeblog 在使用rk3568开发过程&#xff0c;虽然显示的方向已经改成了横屏&#xff0c;但是恢…

4.1k star,官方出品的redis桌面管理工具——redislnsight

导航 令人抓狂的大key加载RedisInsight 简介RedisInsight的亮点GitHub 地址安装和使用RedisInsight 下载安装 使用RedisInsight redis数据库可视化直观的CLI&#xff08;Command-Line Interface&#xff09;日志分析和命令分析 结语参考 令人抓狂的大key加载 工欲善其事必先利…

JavaScript基础4之原型的原型继承、原型链和理解对象的数据属性、访问器属性

JavaScript基础 原型原型继承问题解决 原型链isPrototypeOf()Object.getPrototypeOf() 理解对象数据属性访问器属性 原型 原型继承 继承是面向对象编程的另一个特征&#xff0c;通过继承进一步提升代码封装的程度&#xff0c;JavaScript中大多是借助原型对象实现继承的特性。…

sudo command not found

文章目录 一句话Intro其他操作 一句话 sudo 某命令 改成 sudo -i 某命令 试试。 -i 会把当前用户的环境变量带过去&#xff0c;这样在sudo的时候&#xff0c;有更高的权限&#xff0c;有本用户的环境变量(下的程序命令)。 -i, --login run login shell as the target user; a …

软件测试相关概念和bug的相关总结

文章目录 什么是测试什么是需求测试用例(CASE)什么是BUG软件的生命周期开发模型瀑布模型螺旋模型增量模型和迭代模型 敏捷测试模型v模型W模型(双V模型) 软件测试的生命周期如何描述一个bugbug的级别bug的生命周期.产生争执怎么办 什么是测试 测试是测试人员用来检验软件的实际运…

全自动玻璃切割机控制系统设计

目 录 摘 要 I Abstract II 引 言 1 1 玻璃切割机控制系统设计 4 1.1系统方案选择 4 1.2玻璃切割机的工作原理 4 1.3工艺过程 5 1.4玻璃切割机的控制要求 6 2硬件设计 8 2.1控制部分设计 8 2.2驱动部分设计 8 2.2.1步进电机及驱动器的选型 8 2.2.2步进电机驱动器接口电路设计 …

VM 虚拟机 ubuntu 解决无法连接网络问题

添加网卡法 就是在虚拟机的设置那里多增加一个网卡

每日OJ题_链表②_力扣24. 两两交换链表中的节点

目录 力扣24. 两两交换链表中的节点 解析代码 力扣24. 两两交换链表中的节点 24. 两两交换链表中的节点 难度 中等 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&…

顺序表以及单链表

目录 1顺序表&#xff08;规范&#xff09; 2单链表&#xff08;规范&#xff09; 3总结 1顺序表&#xff08;规范&#xff09; #include<iostream> using namespace std; #define MAXSIZE 100 #define ok -1 #define error -2 typedef int Status; typedef int…

支小蜜校园防欺凌系统如何有效应对学生霸凌?

学生霸凌不仅直接伤害到被霸凌者的身心健康&#xff0c;也对整个校园的和谐氛围构成了威胁。为了应对这一问题&#xff0c;校园防欺凌系统应运而生&#xff0c;成为维护校园安全、保护学生权益的重要工具。那么当校园防欺凌系统面对学生霸凌时&#xff0c;该如何有效应对呢&…