04-MybatisPlus篇
概述
需要的基础:把我的MyBatis、Spring、SpringMVC就可以学习这个了!
为什么要学习它呢?MyBatisPlus可以节省我们大量工作时间,所有的CRUD代码它都可以自动化完成!
狂神说-MybatisPlus视频
简介
MyBatis 本来就是简化 JDBC 操作的!
MyBatis Plus,简化 MyBatis !
官方:https://baomidou.com/

特性
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作, BaseMapper
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求, 以后简单的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 操作智能分析阻断,也可自定义拦截规则,预防误 操作
快速入门
教程:https://baomidou.com/pages/226c21/
步骤
创建数据库
mybatis_plus
User 表,其表结构如下:
1
Jone
18
test1@baomidou.com
2
Jack
20
test2@baomidou.com
3
Tom
28
test3@baomidou.com
4
Sandy
21
test4@baomidou.com
5
Billie
24
test5@baomidou.com
编写项目,初始化项目!使用SpringBoot初始化!



导入依赖
mybatis-plus可以节省大量的代码,mybatis与mybatis-plus尽量不要同时导入,会存在版本差异。
连接数据库!这一步和 mybatis 相同!

传统方式pojo、dao(链接mybatis,配置mapper.xml)、service、controller
使用了mybatis-plus之后
pojo
mapper接口
最好使用@Mapper进行注册,后面就不需要使用@MapperScan
注意点,需要在主启动类上去扫描我们的mapper包下的所有接口
在mapper层使用@Mapper就不需要扫描了
测试类中测试

配置日志
所有的sql现在是不可见的,希望知道它是怎么执行的,所以必须要看日志!

CRUD操作
插入操作

数据库插入的id的默认值为:全局的唯一id
主键生成策略
默认ID_WORKER全局唯一id
分布式系统唯一id生成:https://www.cnblogs.com/haoxinyue/p/5208136.html
雪花算法: snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为 毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味 着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯 一!
主键自增
实体类字段上 添加
@TableId(type = IdType.AUTO)
修改主键字段id为自增,数据库字段一定要是自增!

测试

IdType其他类型字段
自定义ID生成器
更新操作
updateById(Object):根据id进行更新,参数为对象

update(Object,Wrapper)根据指定Wrapper参数进行更新Object

自动填充
创建时间、修改时间!这些个操作一遍都是自动化完成的,我们不希望手动更新!
阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需 要自动化!
方式一:数据库级别(工作中不允许你修改数据库)
在表中新增字段 create_time, update_time

再次测试插入方法,我们需要先把实体类同步!
再次更新查看结果

方式二:代码级别
删除数据库的默认值、更新操作!

实体类字段属性上需要增加注解
编写处理器来处理这个注解即可!
创建handler包,在包下面创建MyMetaObjectHandler.java
测试插入
测试更新、观察时间即可!

乐观锁
在面试过程中,我们经常会被问道乐观锁,悲观锁!这个其实非常简单!
乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题, 再次更新值测试
悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!
这里主要讲解 乐观锁机制!
乐观锁实现方式:
取出记录时,获取当前 version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败
给数据库中增加version字段!

实体类加对应的字段
注册组件
测试一下!
测试乐观锁成功
测试乐观锁失败!

查询操作
根据id查询
根据多个id查询
根据map条件查询
分页操作
原始的 limit 进行分页
pageHelper 第三方插件
内置分页插件
在
MybatisPlusConfig.java中添加分页插件
直接使用Page对象即可!
默认分页
根据wrapper条件分页
删除操作
根据id删除记录
通过id批量删除
通过map删除
在工作中会遇到一些问题:逻辑删除!
逻辑删除
物理删除 :从数据库中直接移除
逻辑删除 :再数据库中没有被移除,而是通过一个变量来让他失效! deleted = 0 => deleted = 1
在数据表中增加一个 deleted 字段

实体类中增加相应属性
MybatisPlusConfig.java中配置逻辑删除组件
高版本不用配置插件了,上述java代码无需编写。
配置参数
测试下删除

发现,现在没有实行删除了,而是进行了更新操作。
性能分析插件
我们在平时的开发中,会遇到一些慢sql。测试! druid…..
作用:该功能依赖 p6spy 组件,完美的输出打印 SQL 及执行时长 3.1.0 以上版本
MP也提供性能分析插件,如果超过这个时间就停止运行!
导入插件
application.properties配置
添加 spy.properties配置文件,在resources目录下
运行查询测试

条件构造器
十分重要:Wrapper
写一些复杂的sql就可以使用它来替代!
AbstractWrapper
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类 用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件 注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为
allEq
例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 : 过滤函数,是否允许字段传入比对条件中 params 与 null2IsNull : 同上
例1:
allEq((k,v) -> k.indexOf("a") >= 0, {id:1,name:"老王",age:null})--->name = '老王' and age is null例2:
allEq((k,v) -> k.indexOf("a") >= 0, {id:1,name:"老王",age:null}, false)--->name = '老王'
eq
等于 =
例:
eq("name", "老王")--->name = '老王'
ne
不等于 <>
例:
ne("name", "老王")--->name <> '老王'
gt
大于 >
例:
gt("age", 18)--->age > 18
ge
大于等于 >=
例:
ge("age", 18)--->age >= 18
lt
小于 <
例:
lt("age", 18)--->age < 18
le
小于等于 <=
例:
le("age", 18)--->age <= 18
between
BETWEEN 值1 AND 值2
例:
between("age", 18, 30)--->age between 18 and 30
notBetween
NOT BETWEEN 值1 AND 值2
例:
notBetween("age", 18, 30)--->age not between 18 and 30
like
LIKE '%值%'
例:
like("name", "王")--->name like '%王%'
notLike
NOT LIKE '%值%'
例:
notLike("name", "王")--->name not like '%王%'
likeLeft
LIKE '%值'
例:
likeLeft("name", "王")--->name like '%王'
likeRight
LIKE '值%'
例:
likeRight("name", "王")--->name like '王%'
isNull
字段 IS NULL
例:
isNull("name")--->name is null
isNotNull
字段 IS NOT NULL
例:
isNotNull("name")--->name is not null
in
字段 IN (value.get(0), value.get(1), ...)
例:
in("age",{1,2,3})--->age in (1,2,3)
字段 IN (v0, v1, ...)
例:
in("age", 1, 2, 3)--->age in (1,2,3)
notIn
字段 NOT IN (value.get(0), value.get(1), ...)
例:
notIn("age",{1,2,3})--->age not in (1,2,3)
字段 NOT IN (v0, v1, ...)
例:
notIn("age", 1, 2, 3)--->age not in (1,2,3)
inSql
字段 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)
notInSql
字段 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)
groupBy
分组:GROUP BY 字段, ...
例:
groupBy("id", "name")--->group by id,name
orderByAsc
排序:ORDER BY 字段, ... ASC
例:
orderByAsc("id", "name")--->order by id ASC,name ASC
orderByDesc
排序:ORDER BY 字段, ... DESC
例:
orderByDesc("id", "name")--->order by id DESC,name DESC
orderBy
排序:ORDER BY 字段, ...
例:
orderBy(true, true, "id", "name")--->order by id ASC,name ASC
having
HAVING ( sql语句 )
例:
having("sum(age) > 10")--->having sum(age) > 10例:
having("sum(age) > {0}", 11)--->having sum(age) > 11
func
func 方法(主要方便在出现if...else下调用不同方法能不断链)
例:
func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})
or
拼接 OR
注意事项:
主动调用
or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)例:
eq("id",1).or().eq("name","老王")--->id = 1 or name = '老王'
OR 嵌套
例:
or(i -> i.eq("name", "李白").ne("status", "活着"))--->or (name = '李白' and status <> '活着')
and
AND 嵌套
例:
and(i -> i.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' and status <> '活着')
nested
正常嵌套 不带 AND 或者 OR
例:
nested(i -> i.eq("name", "李白").ne("status", "活着"))--->(name = '李白' and status <> '活着')
apply
拼接 sql
注意事项:
该方法可用于数据库函数 动态入参的
params对应前面applySql内部的{index}部分.这样是不会有sql注入风险的,反之会有!例:
apply("id = 1")--->id = 1例:
apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")例:
apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
last
无视优化规则直接拼接到 sql 的最后
注意事项:
只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用
例:
last("limit 1")
exists
拼接 EXISTS ( sql语句 )
例:
exists("select id from table where age = 1")--->exists (select id from table where age = 1)
notExists
拼接 NOT EXISTS ( sql语句 )
例:
notExists("select id from table where age = 1")--->not exists (select id from table where age = 1)
QueryWrapper
继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件 及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取
select
设置查询字段
说明:
以上方法分为两类. 第二类方法为:过滤查询字段(主键除外),入参不包含 class 的调用前需要
wrapper内的entity属性有值! 这两类方法重复调用以最后一次为准例:
select("id", "name", "age")例:
select(i -> i.getProperty().startsWith("test"))
UpdateWrapper
继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件 及 LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!
set
SQL SET 字段
例:
set("name", "老李头")例:
set("name", "")--->数据库字段值变为空字符串例:
set("name", null)--->数据库字段值变为null
setSql
设置 SET 部分 SQL
例:
setSql("name = '老李头'")
lambda
获取
LambdaWrapper在QueryWrapper中是获取LambdaQueryWrapper在UpdateWrapper中是获取LambdaUpdateWrapper
使用 Wrapper 自定义SQL
需要mybatis-plus版本 >= 3.0.7 param 参数名要么叫ew,要么加上注解@Param(Constants.WRAPPER) 使用${ew.customSqlSegment} 不支持 Wrapper 内的entity生成where语句
kotlin持久化对象定义最佳实践
由于kotlin相比于java多了数据对象(data class),在未说明情况下可能会混用。建议按照以下形式定义持久化对象
注意:这里的TableId及TableField并非必要,只是为了展示Mybatis-Plus中的annotation使用
这里所有成员都需要定义为可空类型(?),并赋予null的初始值,方便我们在以下场景中使用(类似java中的updateSelective)
不建议使用data class及全参数构造方法,这样我们会写很多不必要的null来构造一个空对象
用注解
用XML
kotlin使用wrapper
kotlin 可以使用
QueryWrapper和UpdateWrapper但无法使用LambdaQueryWrapper和LambdaUpdateWrapper如果想使用 lambda 方式的 wrapper 请使用KtQueryWrapper和KtUpdateWrapper
链式调用 lambda 式
代码自动生成器
dao、pojo、service、controller都给我自己去编写完成!
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、 Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
导入依赖
plus代码生成器需要一个模板引擎,velocity和freemarker任选一个,velocity是生成器中默认使用的,根据你的选择引依赖。
写一个构造器类
生成模板
官方快速生成模板
官方交互式生成模板
代码配置
运行
最后更新于
这有帮助吗?
