教程来源链接: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?
- MyBatis 是一款优秀的持久层框架,说白话就是一款操作数据库的框架。
- 它支持自定义 SQL、存储过程以及高级映射
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- 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表
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
开头,并且功能更丰富,来看看都提供了哪些方法:
// 新增数据
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封装的删除方法:
// 根据 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);
类型 | 参数名 | 描述 |
---|---|---|
Serializable | id | 主键 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);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Serializable | id | 主键 ID |
Wrapper<T> | queryWrapper | 实体对象封装操作类 QueryWrapper |
boolean | throwEx | 有多个 result 是否抛出异常 |
T | entity | 实体对象 |
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
:
3.5.4Page类说明
该类继承了 IPage
类,实现了 简单分页模型 ,如果你要实现自己的分页模型可以继承 Page
类或者实现 IPage
类
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
records | List | emptyList | 查询数据列表 |
total | Long | 0 | 查询列表总记录数 |
size | Long | 10 | 每页显示条数,默认 10 |
current | Long | 1 | 当前页 |
orders | List | emptyList | 排序字段信息,允许前端传入的时候,注意 SQL 注入问题,可以使用 SqlInjectionUtils.check(...) 检查文本 |
optimizeCountSql | boolean | true | 自动优化 COUNT SQL 如果遇到 jSqlParser 无法解析情况,设置该参数为 false |
optimizeJoinOfCountSql | boolean | true | 自动优化 COUNT SQL 是否把 join 查询部分移除 |
searchCount | boolean | true | 是否进行 count 查询,如果指向查询到列表不要查询总记录数,设置该参数为 false |
maxLimit | Long | 单页分页条数限制 | |
countId | String | xml 自定义 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
:
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);
}
4.核心功能
4.1常用注解
Mybatis Plus中常用注解有:
- @TableName:表名注解,标识实体类对应的表
- @TableId:主键注解
- @IdType:指定主键ID类型
- @TableField:指定数据库字段注解(非主键)。
- @TableLogic:逻辑删除注释
- @Version:乐观锁
4.1.1@TableName
- 作用:表名注解,标识实体类对应的表
- 不用添加该注解的两种方式:
- 当表名和实体类的命名一致时,如表名
user
, 实体类为User
时,可不用添加@TableName
注解 - 通过全局配置声明表明前缀(以下例子演示数据库表均为wms_开头)
- 当表名和实体类的命名一致时,如表名
mybatis-plus: global-config:db-config:table-prefix: wms_
4.1.2@TableId
-
作用:主键注解
-
举例
4.1.3@IdType
-
作用:指定主键ID类型
-
各种值情况:
值 描述 AUTO
数据库 ID
自增NONE
未设置主键类型(默认) INPUT
插入数据前,需自行设置主键的值 ASSIGN_ID
分配 ID
(主键类型为Number
(Long
和Integer
)或String
)(since 3.3.0),使用接口IdentifierGenerator
的方法nextId
(默认实现类为DefaultIdentifierGenerator
雪花算法)ASSIGN_UUID
分配 UUID
,主键类型为String
(since 3.3.0),使用接口IdentifierGenerator
的方法nextUUID
(默认default
方法)ID_WORKER
分布式全局唯一 ID 长整型类型 (推荐使用 ASSIGN_ID
)UUID
32 位 UUID 字符串 (推荐使用 ASSIGN_UUID
)ID_WORKER_STR
分布式全局唯一 ID 字符串类型 (推荐使用 ASSIGN_ID
)
4.1.4@TableField
-
作用:指定数据库字段注解(非主键)
-
举例
4.1.5@TableLogic
-
作用:逻辑删除
-
举例
4.2Wrapper条件构造器
4.2.1介绍
- 在 Mybatis Plus 中,利用条件构造器
Wrapper
可以帮助我们组装各种where
条件,具体实现类如QueryWrapper
、UpdateWrapper
等,在查询、更新、删除操作中会被频繁用到。
4.2.2Wrapper继承关系
Wrapper 是个抽象类,先看下它的继承关系图:
解释各个子类作用:
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
- AbstractWrapper是QueryWrapper (LambdaQueryWrapper) 和 UpdateWrapper (LambdaUpdateWrapper) 的父类
- 用于生成 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问题
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语句:
功能正常,相比较上面需要写一堆 if
判断,我们可以直接将判断条件传给 condition
参数,代码看上去舒服多了