入门
简介
Mybatis-Plus(简称:MP),是一个Mybatis的增强工具,在Mybatis的基础上只做增强,不做改
变,为简化开发、提高效率而生
特性
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误
操作
代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、
Mapper、 XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
public void generator(){
FastAutoGenerator.create("jdbc:mysql://localhost:3306/drj",
"root", "xxxx")
.globalConfig(builder -> {
builder.author("dairuijie") // 设置作者
.enableSwagger() // 开启 swagger 模式// .fileOverride() // 覆盖已生成文件,默认值:false
.disableOpenDir() //禁止打开输出目录,默认值:true
.dateType(DateType.ONLY_DATE) //定义生成的实体 类中日期类型 时间策略 DateType.ONLY_DATE 默认值: DateType.TIME_PACK
.outputDir("D:\\mpdemo" +
"/src/main/java"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.chonger.eg") // 设置父包名
.moduleName("user3") // 设置父包模块名表名注解,应用于类上
.pathInfo(Collections.singletonMap(OutputFile.mapperXml,
"D:\\mpdemo" + "/src/main/resources/mapper")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("ym_user") // 设置需要生成的表名
.addTablePrefix("ym_"); // 设置过滤表前缀
builder.entityBuilder()
.naming(NamingStrategy.underline_to_camel)// 数据库表映射到实体的命名策略.默认下划线转驼峰命名
.columnNaming(NamingStrategy.underline_to_camel)//数据库表字段映射到实体的命名策略,默认为 null,未指定按照 naming 执行
.addTableFills(new Column("createTime",
FieldFill.INSERT))
.addTableFills(new Property("updateTime",
FieldFill.INSERT_UPDATE))
.idType(IdType.AUTO) //主键策略
.enableLombok();//开启 lombok 模型,默认 值:false
builder.controllerBuilder()
.enableHyphenStyle()//开启驼峰转连字符,默认 值:false
.enableRestStyle();//开启生成@RestController 控制器,默认值:false
builder.serviceBuilder()
.formatServiceImplFileName("%sServiceImp")// 格式化 service 实现类文件名称
.formatServiceFileName("%sService");//格式化 service 接口文件名称,去掉Service接口的首字母I
})
.strategyConfig(builder -> {
})
// .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
注解配置
TableName
value: 表名,默认为“”
schema:schema,默认为“”
keepGlobalPrefix:是否保持使用全局的tablePrefix值(如果设置了全局tablePrefix且自行设置
了value的值),默认为false
resultMap:xml中resultMap的id,默认为“”
autoResultMap:是否自动构建 resultMap 并使用,默认为false
excludeProperty:需要排除的属性名
以上都为非必输项。
TableId
主键注解,应用于主键字段上
value:主键字段名,默认为“”
type:主键类型,默认为IdType.NONE
以上都为非必输项。
IdType:
AUTO:数据库ID自增
NONE:无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT:insert前自行set主键值
ASSIGN_ID:分配ID,主键类型为Number(Long和Integer)或String,版本
3.3.0以上,使用接口
IdentifierGenerator的方法nextId(默认实现类为
DefaultIdentifierGenerator 雪花算法)
ASSIGN_UUID:分配UUID,主键类型为String,版本3.3.0以上,使用接口
IdentifierGenerator的方法nextUUID
以下已过时,不建议使用:
ID_WORKER:分布式全局唯一ID 长整型类型,使用ASSIGN_ID代替
UUID:32位UUID字符串,使用ASSIGN_UUID代替
ID_WORKER_STR:分布式全局唯一ID 字符串类型,使用ASSIGN_ID代替
TableField
字段注解(非主键)
value:数据库字段名
el:映射为原生#{}逻辑,相当于写在xml中的#{}部分
exist:是否为数据库表字段,默认为true
condition:where查询比较条件,如果设置了值,则获取设置的值,如果没有则默认为全局的-
->%s=#{%s},%s会填充为字段名
参考:链接
update:字段update set部分注入,例如:字段名 = ‘%s+1’,表示更新时,会set
version=version+1
该属性优先级高于el。
insertStrategy:字段验证策略之 insert: 当insert操作时,该字段拼接insert语句时的
策略
IGNORED: 直接拼接
NOT_NULL: 判断是否为空NULL后,在决定是否拼接
NOT_EMPTY: 判断是否为NULL和‘’后,在决定是否拼接
DEFAULT:默认的,一般只用于注解里,在全局里代表 NOT_NULL,在注解里代表 跟
随全局
eg:
insert into table (字段名)
values (#{字段名})
updateStrategy:字段验证策略之 update: 当更新操作时,该字段拼接set语句时的策略
IGNORED: 直接拼接
NOT_NULL:判断是否为空NULL后,在决定是否拼接
NOT_EMPTY:判断是否为NULL和‘’后,在决定是否拼接
DEFAULT:默认的,一般只用于注解里,在全局里代表 NOT_NULL,在注解里代表 跟
随全局
whereStrategy:段验证策略之 where: 表示该字段在拼接where条件时的策略
IGNORED: 直接拼接
NOT_NULL:判断是否为空NULL后,在决定是否拼接
NOT_EMPTY:判断是否为NULL和‘’后,在决定是否拼接
DEFAULT:默认的,一般只用于注解里,在全局里代表 NOT_NULL,在注解里代表 跟
随全局
fill:字段自动填充策略,在对应模式下将会忽略 insertStrategy 或 updateStrategy
的配置,等于断言该字段必有值
FieldFill:
DEFAULT:默认不处理
INSERT:插入时填充字段
UPDATE:更新时填充字段
INSERT_UPDATE:插入和更新时填充字段
select:是否进行 select 查询,值大字段可设置为 false 不加入 select 查询范围,提
高响应效率
keepGlobalFormat:是否保持使用全局的 columnFormat 的值
只生效于既设置了全局的 columnFormat 也设置了上面vaule的值,如果是 false
, 全局的 columnFormat 不生效
jdbcType:JDBC类型,只生效于 mp 自动注入的 method,一般和autoResultMap一起使用
typeHandler:类型处理器,只生效于 mp 自动注入的 method,一般和autoResultMap一起
使用
numericScale:指定小数点后保留的位数,只生效于 mp 自动注入的 method,一般和
autoResultMap一起使用
Version
- 乐观锁注解、在对应的字段上,使用@version注解字段
EnumValue
- 通枚举类注解(注解在枚举字段上)
TableLogic
-
表字段逻辑处理注解
-
逻辑删除字段上 value:未删除的值 delval:已删除的值
-
一般在3.3.0版本以上,此注解建议过时,可直接在springboot的配置文件中,一次性指定逻辑字段、未删除的值和已删除的值
逻辑删除
全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
mybatis-plus.global-config.db-config.logic-delete-field= 逻辑删除的字段名
逻辑已删除值(默认为 1) mybatis-plus.global-config.db-config.logic-delete-value=1
逻辑未删除值(默认为 0) mybatis-plus.global-config.db-config.logic-not-delete-value=0
KeySequence主键
- 序列主键策略,作用于类上
value:序列名
dbType:数据库类型,未配置默认使用注入 IKeyGenerator 实现,多个实现必须指定
OrderBy
- 内置 SQL 默认指定排序
- 优先级低于 wrapper 条件查询
isDesc:是否倒序查询,默认true,false为正序
ase:默认false
sort:数字越小越靠前,默认Short.MAX_VALUE
API功能
说明
- 一般简单的CRUD操作,我们可以直接使用mapper接口进行操作,无需写xml和service
- 但是在常规企业研发中,一般我们会涉及很多复杂的sql和业务,以及规范要求,不写xml和service则无法满足所以,一般我们会进行封装IService接口,进一步封装CRUD接口,采用更符合规范的命名来进行API书写,避免和mapper接口混淆
- 同样,也有对应的 T 泛型,为任意实体对象
- 创建自己的IService继承Mybatis-plus提供的基类
- 对象Wrapper为条件构造器
IService层API
save
boolean save(T entity);
// 插入(批量,一次性插入)
boolean saveBatch(Collection<T> entityList);//执行1条sql,将数据全部一次性插入
// 插入(批量,batchSize:插入批次数量,默认批次提交数量=1000)
boolean saveBatch(Collection<T> entityList, int batchSize);//可查看控制台日志,
例如batchSize=2,则执行了2条sql
saveOrUpdate
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);//先执行update,如
果为0,则执行insert
// 批量修改插入,没执行一条数据,都先SELECT,然后update或者insert
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入,batchSize:插入批次数量,默认批次提交数量=1000
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
Remove
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据实体(ID)删除
boolean removeById(T entity);
// 根据 columnMap 条件,表字段 map 对象,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList)
Update
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新,1条sql执行
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新,batchSize条sql执行
boolean updateBatchById(Collection<T> entityList, int batchSize);
Get
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,取一条加上限制条件
wrapper.last("LIMIT 1")
// 随机取则加:order by rand() limit 1
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录,有多个 result 是否抛出异常,如果为false则输出多个记
录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V>
mapper);
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);
// 查询所有列表
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);
Page
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);
Count
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
Chain
QueryChainWrapper<T> query();
// 链式查询 lambda 式。注意:不支持 Kotlin
LambdaQueryChainWrapper<T> lambdaQuery();
// 示例:
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list()
// 链式更改 普通
UpdateChainWrapper<T> update();
// 链式更改 lambda 式。注意:不支持 Kotlin
LambdaUpdateChainWrapper<T> lambdaUpdate();
// 示例:
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);
Mapper层API
insert
int insert(T entity);
delete
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends
Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
Select
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends
Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object>
columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T>
queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T>
queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page,
@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
Update
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER)
Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
条件表达构造器
- boolean condition:表示该条件是否加入最后生成的sql中
- 不支持以及不赞成在 RPC 调用中把 Wrapper 进行传输。wrapper 很重,正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作
- QueryWrapper和UpdateWrapper都是用于生成sql的where条件,包含Lambda