注
- MybatisPlus3.4.1,注意版本差异
- 个人基于"狂神说"教学视频的学习笔记,可能存在一定纰漏和错误
- 部分内容来在MP官网和其他网络资源
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
框架架构
=====================================
-----------
Scan Entity
-----------
|
Reflection extraction
|
v
-------------------------- ==============MybatisPlus==============
Analysis Table Name Column --------------------------------
-------------------------- mybatis-plus-boot-starter
| --------------------------------
SQL:Insert、Update、Delete、Select 《---- ------------ ------------
| annotation extension
v ------------ ------------
--------------------------- ------------ ------------
Injection Mybatis Container core generator
--------------------------- ------------ ------------
===================================== ======================================
依赖
会自动维护Mybatis,不用再添加Mybatis的依赖
<!--单独使用-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>xxx</version>
</dependency>
<!--集成SpringBoot-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>xxx</version>
</dependency>
案例application.yml基础配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mp
username: root
password: 123456
mybatis:
mybatis-plus:
configuration:
#驼峰:默认为true
map-underscore-to-camel-case: true
#日志,:默认实现,打印到控制台
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
案例表
CREATE TABLE `mp` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`last_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gender` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`age` int(0) NULL DEFAULT NULL,
`create_time` datetime(0) NULL DEFAULT NULL,
`update_time` datetime(0) NULL DEFAULT NULL,
`version` int(0) NULL DEFAULT 1 COMMENT '乐观锁字段',
`deleted` int(0) NULL DEFAULT 0 COMMENT '逻辑删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
案例实体类
/**
* MybatisPlus会默认使用实体类的类名到数据库中找对应的表
* @TableName:
* value:表名(默认为空)
* resultMap:xml字段映射 resultMap的ID
*/
@TableName("mp")
@Data
public class Mp {
/**
* @TableId:
* value:指定表的主键名,若实体类属性和主键字段名相同,可省略
* type:指定主键策略
*/
@TableId(type = IdType.AUTO)
private Integer id;
private String lastName;
private String email;
private Integer gender;
private Integer age;
//字段填充
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
//乐观锁字段
@Version
private Integer version;
/**
* 逻辑删除注解
* @TableLogic
* value:未删除值
* delval:已删除值
* 也可在application.yml全局配置
* mybatis-plus.global-config.db-config.logic-delete-value=
* mybatis-plus.global-config.db-config.logic-not-delete-value=
*/
@TableLogic(value = "0",delval = "1")
private Integer deleted;
}
1.注解说明
注解类包:mybatis-plus-annotation
@TableName
- 描述:表名注解。MP默认使用实体类的类名到数据库中找对应的表。
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 表名 |
schema | String | 否 | “” | schema |
keepGlobalPrefix | boolean | 否 | false | 是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值) |
resultMap | String | 否 | “” | xml 中 resultMap 的 id |
autoResultMap | boolean | 否 | false | 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入) |
excludeProperty | String[] | 否 | {} | 需要排除的属性名(@since 3.3.1) |
关于autoResultMap
的说明:
mp会自动构建一个ResultMap
并注入到mybatis里(一般用不上).下面讲两句: 因为mp底层是mybatis,所以一些mybatis的常识你要知道,mp只是帮你注入了常用crud到mybatis里 注入之前可以说是动态的(根据你entity的字段以及注解变化而变化),但是注入之后是静态的(等于你写在xml的东西) 而对于直接指定typeHandler
,mybatis只支持你写在2个地方:
- 定义在resultMap里,只作用于select查询的返回结果封装
- 定义在
insert
和update
sql的#{property}
里的property
后面(例:#{property,typehandler=xxx.xxx.xxx}
),只作用于设置值
而除了这两种直接指定typeHandler
,mybatis有一个全局的扫描你自己的typeHandler
包的配置,这是根据你的property
的类型去找typeHandler
并使用.
@TableId
-
描述:主键注解
属性 类型 必须指定 默认值 描述 value String 否 “” 主键字段名,若实体类属性和主键字段名相同,可省略 type Enum 否 IdType.NONE 主键类型 -
type
值 描述 IdType.AUTO 数据库ID自增 IdType.NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT,雪花算法) IdType.INPUT insert前自行set主键值 IdType.ASSIGN_ID 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口 IdentifierGenerator
的方法nextId
(默认实现类为DefaultIdentifierGenerator
雪花算法)IdType.ASSIGN_UUID 分配UUID,主键类型为String(since 3.3.0),使用接口 IdentifierGenerator
的方法nextUUID
(默认default方法)
-
@TableField
-
描述:字段注解(非主键)
属性 类型 必须指定 默认值 描述 value String 否 “” 数据库字段名 el String 否 “” 映射为原生 #{ ... }
逻辑,相当于写在 xml 里的#{ ... }
部分exist boolean 否 true 是否为数据库表字段 condition String 否 “” 字段 where
实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的%s=#{%s}
,参考(opens new window)update String 否 “” 字段 update set
部分注入, 例如:update="%s+1":表示更新时会set version=version+1(该属性优先级高于el
属性)insertStrategy Enum N DEFAULT 举例:NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategy Enum N DEFAULT 举例:IGNORED: update table_a set column=#{columnProperty}
whereStrategy Enum N DEFAULT 举例:NOT_EMPTY: where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fill Enum 否 FieldFill.DEFAULT 字段自动填充策略 select boolean 否 true 是否进行 select 查询 keepGlobalFormat boolean 否 false 是否保持使用全局的 format 进行处理 jdbcType JdbcType 否 JdbcType.UNDEFINED JDBC类型 (该默认值不代表会按照该值生效) typeHandler Class<? extends TypeHandler> 否 UnknownTypeHandler.class 类型处理器 (该默认值不代表会按照该值生效) numericScale String 否 “”
关于jdbcType
和typeHandler
以及numericScale
的说明:
numericScale
只生效于 update 的sql. jdbcType
和typeHandler
如果不配合@TableName#autoResultMap = true
一起使用,也只生效于 update 的sql. 对于typeHandler
如果你的字段类型和set进去的类型为equals
关系,则只需要让你的typeHandler
让Mybatis加载到即可,不需要使用注解
@Version
- 描述:乐观锁版本号注解
@TableLogic
- 描述:逻辑删除注解
- 属性:
- value:未删除值
- delval:已删除值
2.通用CRUD
mapper(dao)接口继承com.baomidou.mybatisplus.core.mapper.BaseMapper
接口(BaseMapper<T>,T为封装该接口映射表数据的实体类),其封装了基本通用的CRUD方法。
@Mapper
@Repository
public interface MpMapper extends BaseMapper<Mp> {
}
2.1 Insert
-
BaseMapper.insert(obj)
- 参数:实体类||Wrappe
- 返回值:int,影响的数据库行数
- 注意:自动回写插入数据的id(主键)
@Test public void testCommonInert(){ Mp mp=new Mp(); mp.setLastName("neo"); mp.setEmail("neo@rwby.com"); mp.setGender(0); mp.setAge(20); System.out.println(mapper.insert(mp)); System.out.println(mp.getId()); } ==========sql日志和控制台输出========== ==> Preparing: INSERT INTO mp ( last_name, email, gender, age ) VALUES ( ?, ?, ?, ? ) ==> Parameters: neo(String), neo@rwby.com(String), 0(Integer), 20(Integer) <== Updates: 1 1 9
2.2 Update
-
BaseMapper.updateById(obj)
- 参数:实体类
- 返回值:int,影响的数据库行数
- 注意:作为参数的实体类对象若有属性值为空,则该属性会被忽略
@Test public void testCommonUpdate(){ Mp mp=new Mp(); mp.setId(4); mp.setAge(22); mapper.updateById(mp); } ==========sql日志和控制台输出========== ==> Preparing: UPDATE mp SET age=? WHERE id=? ==> Parameters: 22(Integer), 4(Integer) <== Updates: 1
-
BaseMapper.update(obj,wrapper)
- 参数:实体类&&Wrappe
- 返回值:int,影响的数据库行数
- 注意:作为参数的实体类对象若有属性值为空,则该属性会被忽略,其余属性被用于where子句"="判断。where子句的条件也可通过AbstractWrapper类的方法自定义
@Test public void tesUpdate(){ UpdateWrapper<Mp> wrapper=new UpdateWrapper<>(); wrapper.eq("id",1).set("age",15); mapper.update(null,wrapper); } ==========sql日志和控制台输出========== ==> Preparing: UPDATE mp SET age=? WHERE deleted=0 AND (id = ?) ==> Parameters: 15(Integer), 1(Integer) <== Updates: 1
2.3 Select
-
BaseMapper.selectById(Serializable id)
- 通过id查询
- 参数:实现Serializable 接口的obj
- 返回值:BaseMapper接口传入的泛型T
@Test public void testCommonSelect(){ System.out.println(mapper.selectById(4)); } ==========sql日志和控制台输出========== ==> Preparing: SELECT id,last_name,email,gender,age FROM mp WHERE id=? ==> Parameters: 4(Integer) <== Columns: id, last_name, email, gender, age <== Row: 4, neo, neo@rwby.com, 0, 22 <== Total: 1 Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
-
BaseMapper.SelectOne(Wrapper<T> queryWrapper)
- 通过条件构造器查询一个
- 参数:QueryWrapper
- 返回值:T
- 注意:当
new QueryWrapper(T)
时,根据T的非空属性进行查询,最多只能查询一个,查询结果为多个时报错
@Test public void testSelectOne(){ //通过多个字段查询 Mp mp=new Mp(); mp.setId(4); mp.setLastName("neo"); Wrapper queryWrapper=new QueryWrapper(mp); System.out.println(mapper.selectOne(queryWrapper)); } ==========sql日志和控制台输出========== ==> Preparing: SELECT id,last_name,email,gender,age FROM mp WHERE id=? AND last_name=? ==> Parameters: 4(Integer), neo(String) <== Columns: id, last_name, email, gender, age <== Row: 4, neo, neo@rwby.com, 0, 22 <== Total: 1 Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
-
BaseMapper.selectList(Wrapper<T> queryWrapper)
- 根据条件构造器查询多个
- 参数:QueryWrapper
- 返回值:List<T>
- 注意:
- QueryWrapper为null时,查询所有
- 当
new QueryWrapper(T)
时,根据T的非空属性进行查询
@Test public void testMp(){ mpMapper.selectList(null).forEach(System.out::println); } ==========sql日志和控制台输出========== ==> Preparing: SELECT id,last_name,email,gender,age FROM mp ==> Parameters: <== Columns: id, last_name, email, gender, age <== Row: 1, Tom, Tom@cam.com, 1, 22 <== Row: 2, Jerry, Jerry@cam.com, 1, 25 <== Row: 3, Ruby, Ruby@rwby.com, 0, 19 <== Row: 4, neo, neo@rwby.com, 0, 22 <== Total: 4 Mp{id=1, lastName='Tom', email='Tom@cam.com', gender=1, age=22} Mp{id=2, lastName='Jerry', email='Jerry@cam.com', gender=1, age=25} Mp{id=3, lastName='Ruby', email='Ruby@rwby.com', gender=0, age=19} Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
-
BaseMapper.selectBatchIds(Collection<? extends Serializable> idList)
- 通过id集合查询
- 参数:Collection<? extends Serializable>
- 返回值:List<?>
@Test public void testSelectBatchIds(){ List<Integer> ids=new ArrayList(){{add(1);add(2);add(3);add(4);}}; mapper.selectBatchIds(ids).forEach(System.out::println); } ==========sql日志和控制台输出========== ==> Preparing: SELECT id,last_name,email,gender,age FROM mp WHERE id IN ( ? , ? , ? , ? ) ==> Parameters: 1(Integer), 2(Integer), 3(Integer), 4(Integer) <== Columns: id, last_name, email, gender, age <== Row: 1, Tom, Tom@cam.com, 1, 22 <== Row: 2, Jerry, Jerry@cam.com, 1, 25 <== Row: 3, Ruby, Ruby@rwby.com, 0, 19 <== Row: 4, neo, neo@rwby.com, 0, 22 <== Total: 4 Mp{id=1, lastName='Tom', email='Tom@cam.com', gender=1, age=22} Mp{id=2, lastName='Jerry', email='Jerry@cam.com', gender=1, age=25} Mp{id=3, lastName='Ruby', email='Ruby@rwby.com', gender=0, age=19} Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
-
BaseMapper.selectByMap( Map<String, Object> columnMap)
- 通过Map封装条件查询
- 参数:Map<String, Object>
- 返回值:List<T>,T为BaseMapper接口传入的泛型
- 注意: Key,表字段名;Value,字段取值(条件)。columnMap为null时,查询所有
@Test public void testSelectByMap(){ Map<String,Object> columnMap=new HashMap(); columnMap.put("last_name","Tom"); columnMap.put("gender",1); mapper.selectByMap(columnMap).forEach(System.out::println); } ==========sql日志和控制台输出========== ==> Preparing: SELECT id,last_name,email,gender,age FROM mp WHERE gender = ? AND last_name = ? ==> Parameters: 1(Integer), Tom(String) <== Columns: id, last_name, email, gender, age <== Row: 1, Tom, Tom@cam.com, 1, 22 <== Total: 1 Mp{id=1, lastName='Tom', email='Tom@cam.com', gender=1, age=22}
-
BaseMapper.selectPage(E page, Wrapper<T> queryWrapper)
- 分页查询
- 参数:
- com.baomidou.mybatisplus.extension.plugins.pagination.Page<T>
- new Page(current,size)
- current,当前页
- size,每页显示条数,默认 10
- new Page(current,size)
- QueryWrapper(T)
- com.baomidou.mybatisplus.extension.plugins.pagination.Page<T>
- 返回值:Page
- 注意:
- 不是通过limit进行分页查询,而是使用Mybatis的RowBounds进行内存分页
- QueryWrapper为空时,查询所有
@Test public void testSelectPage(){ mapper.selectPage(new Page<>(1,4),null) .getRecords().forEach(System.out::println); } ==========sql日志和控制台输出========== ==> Preparing: SELECT id,last_name,email,gender,age FROM mp ==> Parameters: <== Columns: id, last_name, email, gender, age <== Row: 1, Tom, Tom@cam.com, 1, 22 <== Row: 2, Jerry, Jerry@cam.com, 1, 25 <== Row: 3, Ruby, Ruby@rwby.com, 0, 19 <== Row: 4, neo, neo@rwby.com, 0, 22 <== Total: 4 Mp{id=1, lastName='Tom', email='Tom@cam.com', gender=1, age=22} Mp{id=2, lastName='Jerry', email='Jerry@cam.com', gender=1, age=25} Mp{id=3, lastName='Ruby', email='Ruby@rwby.com', gender=0, age=19} Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
3. 自动填充
“创建时间”、“修改时间”这个操作都是自动化完成的。
3.1 数据库级别
相应字段设置默认值,勾选“自动更新”。
3.2 代码级别
-
在实体类相应属性添加注解**@TableField(fill=FieldFill)**。
- enum FieldFill
- DEFAULT,默认,不自动填充
- INSERT,插入时自动填充
- UPDATE,更新时自动填充
- INSERT_UPDATE,插入和更新时自动填充
@TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
- enum FieldFill
-
编写注解处理器
- 注解**@Component**
- 实现
com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
- 重写对应方法(以insert、update为例)
- 使用
MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
方法- String fieldName:属性(字段)名
- Object fieldVal:字段值
- MetaObject metaObject:处理的数据
- 使用
@Slf4j @Component public class FillHandler implements MetaObjectHandler { //插入的填充策略 @Override public void insertFill(MetaObject metaObject) { log.info("插入填充"); this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } //更新的填充策略 @Override public void updateFill(MetaObject metaObject) { log.info("更新填充"); this.setFieldValByName("updateTime",new Date(),metaObject); } }
4. 乐观锁
- 乐观锁:总是认为不会出现问题,无论干什么都不上锁。若出现问题,再更新值测试(自旋、CAS)。
- 悲观锁:认为总是出现问题,无论干什么都会先上锁再去操作(synchronized)。
乐观锁实现方式:
- 取出记录,获取当前version(oldVersion)
- 更新时,带上并更新此version
- 执行更新
set version = newVersion where version = oldVersion
若version != oldVersion
,更新失败
4.1 MP实现乐观锁
-
数据库添加记录版本号的字段(数字)
-
实体类对应属性添加**@Version**注解
//乐观锁字段 @Version private Integer version;
-
编写配置类,注册乐观锁拦截器com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor
@Configuration public class OptLockingConfig { //注册乐观锁插件 @Bean public OptimisticLockerInnerInterceptor optLockerInnerInterceptor(){ return new OptimisticLockerInnerInterceptor(); } }
5. 逻辑删除
- 物理删除:从数据库中直接移除
- 逻辑删除:没有从数据库中移除,而是通过一个变量使其失效
5.1 MP实现逻辑删除
-
数据库添加逻辑删除的字段
-
实体类对应属性添加**@TableLogic**注解
@TableLogic(value = "0",delval = "1") /** * value:未删除值 * delval:已删除值 */ private Integer deleted;
-
也可在application.yml中进行全局配置,此时不用再对@TableLogic的属性进行赋值
mybatis-plus: global-config: db-config: #未删除 logic-not-delete-value: 0 #已删除 logic-delete-value: 1
-
测试
本质是更新操作,查询时会自动过滤逻辑删除字段
@Test public void LogicTest(){ mapper.deleteById(1); mapper.selectById(1); } ==========sql日志和控制台输出========== ==> Preparing: UPDATE mp SET deleted=1 WHERE id=? AND deleted=0 ==> Parameters: 1(Integer) <== Updates: 1 ==> Preparing: SELECT id,last_name,email,gender,age,create_time,update_time,version,deleted FROM mp WHERE id=? AND deleted=0 ==> Parameters: 1(Integer) <== Total: 0
6. 性能分析打印插件
性能分析插件PerformanceInterceptor在3.2.0版本被废除,3.2.0以上版本可以使用性能分析打印插件。该插件有性能损耗,建议在测试环境使用。
-
依赖
<dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>3.9.1</version> </dependency>
-
增加配置spy.properties
- 打印出sql为null,在excludecategories增加commit
- 批量操作不打印sql,去除excludecategories中的batch
#3.2.1以上使用 modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory #3.2.1以下使用或者不配置 #modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory # 自定义日志打印 logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger #日志输出到控制台 appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger # 使用日志系统记录 sql #appender=com.p6spy.engine.spy.appender.Slf4JLogger # 设置 p6spy driver 代理 deregisterdrivers=true # 取消JDBC URL前缀 useprefix=true # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. excludecategories=info,debug,result,commit,resultset # 日期格式 dateformat=yyyy-MM-dd HH:mm:ss # 实际驱动可多个 #driverlist=org.h2.Driver # 是否开启慢SQL记录 outagedetection=true # 慢SQL记录标准 2 秒 outagedetectioninterval=2
-
修改application.yml数据源配置
- driver-class-name 为 p6spy 提供的驱动类
- url 前缀为 jdbc:p6spy:对应数据库连接地址
spring: datasource: driver-class-name: com.p6spy.engine.spy.P6SpyDriver url: jdbc:p6spy:mysql://localhost:3306/mp username: *** password: ***
-
测试
@Test public void PerformanceTest(){ mapper.selectById(1); } ==========sql日志和控制台输出========== ==> Preparing: SELECT id,last_name,email,gender,age,create_time,update_time,version,deleted FROM mp WHERE id=? AND deleted=0 ==> Parameters: 1(Integer) Consume Time:15 ms 2021-01-07 21:55:57 Execute SQL:SELECT id,last_name,email,gender,age,create_time,update_time,version,deleted FROM mp WHERE id=1 AND deleted=0 <== Columns: id, last_name, email, gender, age, create_time, update_time, version, deleted <== Row: 1, TomCat, Tom@cam.com, 1, 22, 2021-01-05 20:34:25, 2021-01-05 21:18:00, 1, 0 <== Total: 1
7. 条件构造器Wrapper
Wrapper 条件构造抽象类
-- AbstractWrapper 查询条件封装,用于生成 sql 中的 where 语句。
-- QueryWrapper Entity对象封装操作类,用于查询。
-- UpdateWrapper Update条件封装操作类,用于更新。
-- AbstractLambdaWrapper 使用 Lambda 表达式封装 wrapper
-- LambdaQueryWrapper 使用 Lambda 语法封装条件,用于查询。
-- LambdaUpdateWrapper 使用 Lambda 语法封装条件,用于更新。
这段内容太多了,建议参考官方文档
关于com.baomidou.mybatisplus.core.conditions.Wrapper中的方法,个人理解(仅仅是个人理解)是用于"指导"sql生成,其方法主要是判空(指导生成条件子句)和拼接sql。
一个简单的控制变量
-
Wrapper部分源码
/** * 深层实体判断属性 * * @return true 为空 */ public boolean isEmptyOfEntity() { return !nonEmptyOfEntity(); } /** * 查询条件为空(不包含entity) */ public boolean isEmptyOfNormal() { return CollectionUtils.isEmpty(getExpression().getNormal()); } /** * 查询条件为空(包含entity) */ public boolean isEmptyOfWhere() { return isEmptyOfNormal() && isEmptyOfEntity(); }
-
测试上诉方法
@Test public void wrapper(){ Mp mp1=new Mp(); Mp mp2=new Mp(); mp2.setAge(15); //传入属性全为空的entity,无条件 QueryWrapper<Mp> wrapper1=new QueryWrapper<>(mp1); //传入属性不全为空的entity,无条件 QueryWrapper<Mp> wrapper2=new QueryWrapper<>(mp2); //无entity,有条件 QueryWrapper<Mp> wrapper3=new QueryWrapper<>(); wrapper3.orderByAsc("age"); //无entity,无条件 QueryWrapper<Mp> wrapper4=new QueryWrapper<>(); ... }
-
输出结果
wrapper1,属性全为空的entity,无条件:
entity判空:true
where判空(不包含entity):true
where判空(包含entity):true
wrapper2,属性不全为空的entity,无条件:
entity判空:false
where判空(不包含entity):true
where判空(包含entity):false
wrapper3,无entity,有条件:
entity判空:true
where判空(不包含entity):true
where判空(包含entity):true
wrapper4,无entity,无条件:
entity判空:true
where判空(不包含entity):true
where判空(包含entity):true
8. 代码生成器
依赖
MyBatis-Plus 从 3.0.3
之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖。
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--默认支持的模版-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
demo
生成器相关的包com.baomidou.mybatisplus.generator
/**
* 代码生成器
*/
public class MpAg {
public static void main(String[] args) {
//代码生成器对象
AutoGenerator ag=new AutoGenerator();
//1.全局配置
GlobalConfig gc=new GlobalConfig(); //生成器全局配置对象
String path=System.getProperty("user.dir"); //当前项目路径
gc.setOutputDir(path+"/mp_08_auto_generator/src/main/java/com") //设置输出路径
.setAuthor("asd") //设置作者
.setOpen(false) //生成后是否打开资源管理器(windows文件夹)
.setFileOverride(false) //是否覆盖
.setServiceName("%sService") //设置service层接口名称(去"I"前缀)
.setIdType(IdType.AUTO) //设置主键策略(自增)
.setDateType(DateType.ONLY_DATE) //设置日期类型
.setSwagger2(true); //自动配置Swagger
//2.配置数据源
DataSourceConfig dsc = new DataSourceConfig(); //数据源配置对象
dsc.setDriverName("com.mysql.cj.jdbc.Driver")
.setUrl("jdbc:mysql://localhost:3306/mp")
.setUsername("root")
.setPassword("123456")
.setDbType(DbType.MYSQL);
//3.包配置
PackageConfig pc=new PackageConfig(); //包配置对象
pc.setParent("study.ag") //总路径
.setModuleName("mp") //上级包名
.setEntity("entity") //实体类包名
.setMapper("mapper") //dao层包名
.setService("service") //service层包名
.setServiceImpl("service.impl") //service实现类包名
.setController("controller"); //controller层包名
//4.策略配置
List<TableFill> tableFills=new ArrayList();
tableFills.add(new TableFill("creat", FieldFill.INSERT));
tableFills.add(new TableFill("update", FieldFill.INSERT_UPDATE));
StrategyConfig sc=new StrategyConfig(); //策略配置对象
sc.setInclude("mp") //映射的表
.setNaming(NamingStrategy.underline_to_camel) //表名映射策略(下划线->驼峰)
.setColumnNaming(NamingStrategy.underline_to_camel) //列名映射策略(下划线->驼峰)
//.setSuperXXXClass() 自己的XXX父类,没有则不设置
.setEntityLombokModel(true) //实体类是否开启Lombok
.setRestControllerStyle(true) //Controller是否采用RestFul风格
.setControllerMappingHyphenStyle(true) //url下划线连接
.setLogicDeleteFieldName("deleted") //逻辑删除属性名
.setTableFillList(tableFills) //自动填充(List<TableFill>)
.setVersionFieldName("version"); //乐观锁版本属性名
//将配置放入AutoGenerator
ag.setGlobalConfig(gc)
.setDataSource(dsc)
.setPackageInfo(pc)
.setStrategy(sc);
//执行
ag.execute();
}
}