课程介绍
- 了解MyBatis-Plus
- 整合MyBatis-Plus
- 通用CRUD
- MyBatis-Plus的配置
- 条件构造器
- ActiveRecord
- Mybatis-Plus的插件
- Sql注入器实现自定义全局操作
- 自动填充功能
- 逻辑删除
- 通用枚举
- 代码生成器
- MybatisX快速开发插件
课程目标
- 了解MyBatis-Plus的作用
- 掌握MyBatis+MP的整合
- 掌握Spring+MyBatis+MP的整合
- 掌握SpringBoot+MyBatis+MP整合
- 掌握BaseMapper的通用CRUD方法
- 掌握MP的基本配置
- 掌握MP的进阶配置
- 掌握MP的DB策略配置
- 掌握MP的条件构造器
- 理解ActiveRecord以及使用
- 掌握MP的执行分析插件
- 掌握MP的性能分析插件
- 掌握MP的乐观锁插件
- 掌握Sql注入器
- 掌握自动填充功能
- 掌握逻辑删除
- 理解 通用枚举
- 了解代码生成器
- 了解MybatisX快速开发插件
了解MyBatis-Plus
MyBatis-Plus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做 改变,为简化开发、提高效率而生。
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响
- 损耗小:启动即会自动 注入基本CRUD,性能基本无损耗,直接面向对象操作
- 强大的CRUD操作:内置通用Mapper、通用Service,仅仅通过少量配置即可实现单表大部分CRUD操作,更有强大的条件构造器,满足各类使用需求
- 支持Lambda形式调用:通过Lambda表达式,方便的编写各类查询条件,无需担心字段写错
- 支持各种数据库
- 支持主键自动生成
- 支持XML热加载
- 支持ActiveRecord模式:支持ActiveRecord形式调用,实体类只需继承Model类即可进行强大的CRUD操作
- 支持自定义全局通用操作
- 内置代码生成器
- 内置分页插件
- 内置性能分析插件
- 内置全局拦截插件
- 内置sql注入剥离器
架构

快速开始
对于MyBatis整合MP常常有三种用法,分别是MyBatis+MP、Spring+MyBatis+MP、Spring Boot+MyBatis+MP。
Mybatis实现查询User
==第一步,编写mybatis-config.xml文件==
1 |
|
==第二步,编写User实体对象,使用lombok进行了进化bean操作==
1 |
|
==第三步,编写UserMapper接口==
1 | public interface UserMapper { |
==第四步,编写UserMapper.xml文件==
1 | <mapper namespace="cn.itcast.mp.simple.mapper.UserMapper"> |
==第五步,编写测试用例==
1 |
|
Mybatis+MP实现
==第一步,将UserMapper继承BaseMapper,将拥有了BaseMapper中的所有方法==
1 | public interface UserMapper extends BaseMapper<User> |
==第二步,使用MP中的MybatisSqlSessionFactoryBuilder进程构建==
1 |
|
注意:在User对象中添加@TableName,指定数据库表名
简单说明:由于使用了MybatisSqlSessionFactoryBuilder进行了构建,继承的BaseMapper中的方法就载入到了SqlSession中,所以就可以直接使用相关的方法
Spring+Mybatis+MP
引入了Spring框架,数据源、构建等工作就交给了Spring管理
==第一步,编写jdbc.properties==
==第二步,编写applicationContext.xml==
1 | <!--这里使用MP提供的sqlSessionFactory,完成了Spring与MP的整合--> |
==第三步,编写User对象以及UserMapper接口==
==第四步,编写测试用例==
1 |
|
SpringBoot+Mybatis+MP
使用SpringBoot将进一步的简化MP的整合,需要注意的是,使用SpringBoot需要继承parent
1 | <parent> |
==编写启动类==
1 | //设置mapper接口的扫描包 |
==编写测试用例==
1 |
|
通用CRUD
前面了解到通过继承BaseMapper就可以获取到各种各样的单表操作,接下来将详细讲解这些操作
@TableField
在MP中通过@TableField注解可以指定字段的一些属性,常常解决的问题有2个
对象中的属性名和字段名不一致的问题(非驼峰)
1
2
private String mail;对象中的属性字段在表中不存在的问题
1
2
private String address;
其他用法, 如密码字段不加入查询字段;
更新操作
1 | //根据ID修改 |
删除操作
1 | //根据ID删除 |
查询操作
MP提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分页查询等操作
1 | //根据ID查询 |
SQL注入的原理
MP在启动后会将BaseMapper中的一系列的方法注册到meppedStatements中,那么究竟是如 何注入的呢?流程又是怎么样的?
在MP中,ISqlInjector负责SQL的注入工作,它是一个接口,AbstractSqlInjector是它的实现类。在AbstractSqlInjector中,主要是由inspectInject()方法进行注入的,如下
1 |
|
在实现方法中, methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo)); 是关键,循环遍历方法,进行注入。
最终调用抽象方法injectMappedStatement进行真正的注入
1 | /** |
以SelectById为例查看
1 | public class SelectById extends AbstractMethod { |
可以看到,生成了SqlSource对象,再将SQL通过addSelectMappedStatement方法添加到meppedStatements中
配置
configLocation
如果项目有单独的MyBatis配置,则将其路径配置到configLocation中
Spring Boot
1 | mybatis-plus.config-location = classpath:mybatis-config.xml |
Spring MVC
1 | <bean id="sqlSessionFactory" |
mapperLocations
MyBatis Mapper所对应的XML文件位置
Spring Boot
1 | mybatis-plus.mapper-locations = classpath*:mybatis/*.xml |
Spring MVC
1 | <bean id="sqlSessionFactory" |
Maven多模块项目的扫描路径需以
classpath*:开头(即加载多个jar包下的XML文件)
typeAliasesPackage
Mybatis别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在Mapper对应的XML文件中可以直接使用类名,而不用使用全限定的类名
Spring Boot
1 | mybatis-plus.type-aliases-package = cn.itcast.mp.pojo |
Spring MVC
1 | <bean id="sqlSessionFactory" |
mapUnderscoreToCamelCase
- 类型:
boolean - 默认值:
true
是否开启自动驼峰命名规则映射,即从经典是数据库列名A_COLUMN(下划线命名)到经典Java属性名aColumn(驼峰命名)的类似映射
cacheEnabled
- 类型:
boolean - 默认值:
true
全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为TRUE
idType
- 类型:
com.baomidou.mybatisplus.annotation.IdType - 默认值:
ID_WORKER
全局默认主键类型,设置后,即可省略实体对象中的@Table(type=IdType.AUTO)配置
Spring Boot
1 | mybatis-plus.global-config.db-config.id-type=auto |
SpringMVC
1 | <!--这里使用MP提供的sqlSessionFactory,完成了Spring与MP的整合--> |
tablePrefix
- 类型:
String - 默认值:
null
表名前缀,全局配置后可省略@TableName()配置
SpringBoot
1 | mybatis-plus.global-config.db-config.table-prefix=tb_ |
SpringMVC
1 | <bean id="sqlSessionFactory" |
条件构造器
在MP中,Wrapper接口的实现类关系如下

可以看到,AbstractWrapper和AbstractChainWrapper是重点实现,接下来重点了解AbstractWrapper及其子类
allEq
1 | allEq(Map<R, V> params) |
基本比较操作
- eq:等于
- ne:不等于
- gt:大于
- ge:大于等于
- lt:小于
- le:小于等于
- between
- notBetween
- in
- notIn
模糊查询
- like
- notLike
- likeLeft
- likeRight
排序
- orderBy
- orderByAsc
- orderDesc
逻辑查询
- or
- and
ActiveRecord
简称AR,属于ORM层,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂
AR的主要思想是:
- 每个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field
- AR同时负责把自己持久化,在AR中封装了对数据库的访问,即CURD
- AR是一种领域模型,封装了部分业务逻辑
开启AR之旅
在MP中,开启AR非常简单,只需要将实体对象继承Model即可
1 |
|
根据主键查询
1 |
|
新增数据
1 |
|
更新操作
1 |
|
删除操作
1 |
|
根据条件查询
1 |
|
Oracle主键Sequence
在mysql中,主键往往是自增长的 ,这样使用起来比较方便的,如果使用的是Oracle数据库,那么就不能使用自增长了,就得使用Sequence序列生成id值
1 | #数据库连接配置 |
配置序列
使用Oracle的序列需要做2件事情:
==第一,需要配置MP的序列生成器到Spring容器==
1 |
|
==第二,在实体对象中指定序列的名称==
1 |
|
插件
Mybatis的插件机制
Mybatis允许在已映射语句执行过程中的某一点进行拦截调用。默认情况下,Mybatis允许使用插件来拦截的方法调用包括
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
可以拦截Executor接口的部分方法,比如update,query,commit,rollback等方法
总体概括为:
- 拦截执行器的方法
- 拦截参数的处理
- 拦截结果集的处理
- 拦截Sql语法构建的处理
拦截器示例:
1 |
|
注入到Spring容器:
1 | /** |
或者通过xml配置,mybatis-config.xml
1 | <configuration> |
执行分析插件
在MP中提供了对SQL执行的分析的插件,可用作阻断全表更新、删除的操作,注意:该插件仅用于开发环境,不适用于生产环境
SpringBoot:
1 |
|
性能分析插件
性能分析拦截器,用于输出每条SQL语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常
1 | <configuration> |
乐观锁插件
意图:当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
==插件配置==
spring xml
1 | <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/> |
spring boot
1 |
|
==注解实体字段==
需要为实体字段添加@Version注解
- 为表添加version字段,并且设置初始值 为1
- 为User实体对象添加version字段,并且添加@Version注解
==特别说明==
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1 newVersion会回写到entity中- 仅支持
updateById(id)与update(entity, wrapper)方法 - 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
Sql注入器
在MP中,通过AbstractSqlInjector将BaseMapper中的方法注入到了Mybatis容器,这样这些方法才可以正常执行
==那么,如何扩充BaseMapper中的方法,该如何实现呢?==
编写MyBaseMapper
1 | public interface MyBaseMapper<T> extends BaseMapper<T> { |
编写MySqlInjector
如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,所以选择继承DefaultSqlInjector进行扩展
1 | public class MySqlInjector extends DefaultSqlInjector { |
编写FindAll
1 | public class FindAll extends AbstractMethod { |
注册到Spring容器
1 | /** |
至此,完成了全局扩展SQL注入器
自动填充功能
有时我们需要插入或更新数据时,有些字段能够自动填充数据,比如密码、version等。在MP中提供了这样的功能,可以实现自动填充。
添加@TableField注解
1 | //插入数据时进行填充 |
编写MyMetaObjectHandler
1 |
|
逻辑删除
开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,而并非真正 的物理删除(非DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免 数据被真正的删除。
MP就提供了这样的功能,方便我们使用
修改表结构
为tb_user表增加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除。
1 | ALTER TABLE `tb_user` |
同时,也修改User实体,增加deleted属性并且添加@TableLogic注解
1 |
|
配置
application.properties
1 | # 逻辑已删除值(默认为 1) |