1.Mybatis介绍
在日常开发中应该能发现,单表的CRUD功能代码重复度很高,也没有什么难度。而这部分代码量往往比较大,开发起来比较费时。
因此,目前企业中都会使用一些组件来简化或省略单表的CRUD开发工作。目前在国内使用较多的一个组件就是MybatisPlus。
官方网站如下:
当然,MybatisPlus不仅仅可以简化单表操作,而且还对Mybatis的功能有很多的增强。
==Mybatis——-基础使用==
1.1 pom.xml引入依赖
MybatisPlus提供了starter,实现了自动Mybatis以及MybatisPlus的自动装配功能,坐标如下:
如图所示,由于这个starter包含对mybatis的自动装配,因此完全可以替换掉Mybatis的starter
1.2 定义Mapper层
为了简化单表CRUD,MybatisPlus提供了一个基础的BaseMapper
接口,其中已经实现了单表的CRUD:
我们直接==实现BaseMapper接口==即可
1.3 对比
我们可以看出这样直接调用简单的CRUD方法即可,就不用自己去mapper层写方法和对应xml文件了。==只需要继承BaseMapper就能省去所有的单表CRUD==。
1.4 底层实现原理
刚才①引入依赖和②mapper层继承BaseMapper接口就可以进行CRUD,那MP怎么知道是哪张表?表中有哪些字段?
这也是因为UserMapper在继承BaseMapper的时候指定了一个泛型和数据库对应的实体类
MybatisPlus就是根据PO实体的信息来推断出表的信息,从而生成SQL的。默认情况下:
- MybatisPlus会把PO实体的类名驼峰转下划线作为表名
- MybatisPlus会把PO实体的所有变量名驼峰转下划线作为表的字段名,并根据变量类型推断字段类型
- MybatisPlus会把名为id的字段作为主键
但很多情况下,默认的实现与实际场景不符,因此MybatisPlus提供一些注解便于我们声明表信息
2.常见注解==解决po和mysql字段映射==
==如果不按照约定的话,需要使用以下三种注解来解决:==
MybatisPlus中比较常用的几个注解如下:
•@TableName:用来指定表名
•@TableId:用来指定表中的主键字段信息
•@TableField:用来指定表中的普通字段信息
其中,具体的细节如图所示:==使用查看==
2.1 @TableName
- 描述:表名注解,标识实体类对应的表
- 使用位置:实体类
所有属性:
2.2 @TableId
- 描述:主键注解,标识实体类中的主键字段
- 使用位置:实体类的主键字段
其中type=IdType.xxxx取值范围:
2.3 @TableField
描述:普通字段注解
3.yml常见配置
在application.yml文件配置:
==Mybatis——-核心功能==
刚才都是以id为条件的简单CRUD,一些复杂的SQL语句就需要用到一些高级功能。
1.条件构造器==提供复杂where语句==
修改、删除、查询的SQL语句都需要指定where条件
因此BaseMapper中提供的相关方法除了以id
作为where
条件以外,还支持更加复杂的where
条件。
参数中的Wrapper
就是条件构造的抽象类,其下有很多默认实现,继承关系如图:
其中,Wrapper
的子类AbstractWrapper
提供了where中包含的所有条件构造方法:
而QueryWrapper在AbstractWrapper的基础上拓展了一个select方法,允许指定查询字段:
而UpdateWrapper在AbstractWrapper的基础上拓展了一个set方法,允许指定SQL中的SET部分:
1.1 QueryWrapper
==主要对where语句的条件进行设置==
对于查询:
1 | select id,username,info,balance |
对于修改:
1 | update |
1.2 UpdateWrapper
==弥补BaseMapper中update()只能写 set Xxx==,提出的updatewrapper可以写成set balance=balance-xx这种形式
以更新多个id为例:
1 | update user |
这个set的赋值结果是基于字段现有值,这时候需要使用UpdateWrapper中的==setSql功能:==
1.3 LambdaQueryWrapper
==1.1和1.2会在构造条件时候写死字段名称==,现在1.3就可以通过变量的getter方法结合反射获取
2.自定义SQL
1.2中演示了一个修改余额-200的时候将sql维护应该放在持久层,而不是业务层:
==利用Wrapper生成查询条件,然后再结合mapper自定义xml文件编写sql==
2.1 原位置变化
以刚才案例为例:
2.2 Mapper层方法定义
2.3 写sql语句
方式一:直接在mapper的方法上写@Select方法
方式二:在mapper.xml文件中写动态sql
和以往的区别就是:==where语句直接用${ew.customSqlSegment}替换==
总结如下:
与以往的变化就是我传入参数和where判断条件,mapper方法加一个@Param(“ew”)标志,然后sql里面就直接用${ew.customSqlSegment}替换
3.Service接口
通用接口为==Iservice==,默认实现为==ServiceImpl==。其中封装方法可以分为:
save
:新增remove
:删除update
:更新get
:查询单个结果list
:查询集合结果count
:计数page
:分页查询
3.1 五大类方法解释
3.1.1 新增(save)
3.1.2 删除(remove)
3.1.3 修改(update)
3.1.4 查询
3.4.1 查询一条(get)
3.4.2 查询多条(list)
3.4.3 计数(count)
3.1.5调用mapper层自定义sql
通过getBaseMapper获取Mapper,然后就mapper.自定义sql()
3.6 基本用法
现在的变化就是,==拿现成的直接用==:
具体操作就是:
1 | --保证自定义mapper继承basemapper 【底层使用时候直接还是调用basemapper的方法】 |
3.7 快速搭建(直接看)
==1.业务简单的话直接调用mp方法;==
==2.业务复杂的话就跟原来方式一样,controller调用service方法,然后在mapper层写具体sql==
3.7.1 简单业务-直接调用mp方法
3.7.2 复杂业务-原始模式优化
之后调用mapper层的sql:
3.8 Lambda查询[添加属性]
就是在基本的方法上(属性,最新值)再多使用一个属性(==判断条件==,属性,最新值)
这样就可以把动态sql里面
3.9 批量新增
三种方案:
最推荐第三种我们在yml配置文件中添加&rewriteBatchedStatements=true
==Mybatis——-扩展功能==
1.代码生成
在使用MybatisPlus以后,基础的Mapper
、Service
、PO
代码相对固定,重复编写也比较麻烦
==为了方便生成基本固定的代码==
1.1 下载插件
1.2 配置数据库
1.3 配置信息生成代码
1.4查看代码
2.静态工具—-Db
有一种可能就是有AService用来查询用户和BService用来查询地址,他们都实现了Iservice可以实现一些简单的CRUD。现在需要查询用户和对应的地址,就可能AService调用BService,然后BService也要调用AService就会导致@Autowired时候循环依赖
MybatisPlus提供一个静态工具类:==Db==,==就是用来解决多个service层互相调用导致的循环依赖==,其中一些静态方法与IService中的方法签名基本一致,也可以帮助我们实现CRUD的功能
在使用的时候,就可以直接像平时书写习惯直接调用
3.逻辑删除
多表查询时删除A表的数据同时也会删除B数据,但是B里面有一些比较重要的数据我们不想删除。因此,我们采用==逻辑删除==的方案:
可以考虑在表中添加一个字段flag(标记数据是否被删除),这样我们在删除数据的时候还需要将flag设置为true,如果在查询数据的时候还需要添加一个and flag=xxx的条件。这样的话就会让之前的查询和删除逻辑都要跟着变化,非常麻烦。
因此,MybatisPlus就添加了对逻辑删除的支持。
只有MybatisPlus生成的SQL语句才支持自动的逻辑删除【就是直接拿来用的哪些CRUD方法】
自定义SQL就需要自己手动处理逻辑删除
3.1 配置逻辑删除
我们对于Address表添加一个字段deleted用于判断是否删除:
3.2 底层实现
我们在使用MybatisPlus自己的CRUD方法时候支持自动逻辑删除:
具体的两个语法操作:
1.删除的时候我们就会将delete更改为一个update语句拼接一个deleted=false未被删除的判断
2.查询的时候我们就会在where语句拼接一个deleted=false未被删除的判断
3.3 注意事项
开启逻辑删除功能之后,可以像普通删除一样做CRUD,基本不用考虑代码逻辑功能问题。
但是,逻辑删除本身也有缺点:
- 会导致数据库表垃圾数据越来越多,从而影响查询效率
- sql中全都需要对逻辑删除字段做判断,影响查询效率
==因此,不太建议采用逻辑删除功能,如果数据不能删除,可以采用数据迁移到其他表的办法==
4.枚举处理器(字段有多个值)
对某个字段(0是正常,1是不正常)判断时候如果写==1这样很不美观,并且如果0和1的含义修改了要修改很多地方,因此我们可以使用枚举(很像c语言的参数宏定义)来处理
针对于之前案例User类的status属性,就可以这样修改:
在原始的mybatis底层帮我们把Java中的类型和数据库的类型一一对应,但是对于枚举类型和Json类型无法解决。因此mybatisplus针对枚举和Json类型提出了新的处理器:
4.1 配置枚举处理器
4.2 定义枚举类
这样就可以将1和2分别代表正常和冻结,我们在使用的时候只需要调用UserStatus.NORMAL就可以对比了
此外,@EnumValue可以保证我们可以按照value的类型和数据库一一对应;而@JsonValue可以保证我们输出给前端的时候可以将描述词/对应值返回(而不是返回NORMAL/FORZEN这种类型)
4.3 修改PO和VO类型
主要是将类型Integer改为UserStatus枚举类
4.4 修改具体逻辑位置
原来位置是用数字比对,可读性太差,现在就可以优雅地使用枚举类
5.Json类型处理器(字段是Json类型)
如果实体类有一个属性是Json类型,那么Java中的Json类型和数据库中的匹配就有问题:
就跟4枚举处理器里面将的,MybatisPlus在Myabtis的基础上提供了Json类型处理器
5.1 配置Json类型处理器
因为没有提供在application.yml配置的方式,只能通过给实体类属性添加注解
5.2 测试查看
info字段已经改成了一个Json类型
6.配置加密
目前我们配置文件中很多参数都是明文存储,如果开发人员跑路很容易导致敏感信息泄露。
MyBatisPlus从3.3.2版本开始提供了一个==基于AES算法的加密工具==,帮助我们对配置中的敏感信息做加密处理。
6.1 生成秘钥
以数据库的账户密码为例:
6.2 配置秘钥
在application.yml文件中修改:
6.3 测试
测试类:在测试类的注解上配置:
启动项目:
==Mybatis——-插件功能==
其实MybatisPlus提供了多个插件,而我们重点关注分页插件
1.分页插件
1.1 配置分页功能
1.2 测试简单分页
1.3 测试复杂分页
针对于1.2的话其实就是更针对业务逻辑:
==Mybatis——-使用操作==
1.可以创建好数据库表
2.根据mybatis插件生成:
po(可以添加注解保证数据库和Java实体类对应,对于枚举和Json类型都有新推出的处理器解决),
service(extends IService
serviceImpl( extends ServiceImpl<XxxMapper, Xxx> implements IAddressService), [引入mapper方法:①注入xxxMapper ②直接getBaseMapper]
controller,
mapper(extends BaseMapper
3.按照原有的设计思路写代码:
3.1 简单的就直接调用service的CRUD方法【service接口默认也有实现类ServiceImpl<XXXMapper,实体类>,这样也说明底层还是直接调用BaseMapper方法】
3.2 复杂的话,①xml文件按照原来的动态sql书写
3.3 复杂的话,②使用xxxMapper.条件构造器[创建复杂where语句]
3.4 复杂的话,③使用lambdaQuery()/lambdaUpdate()添加一些where语句 –新特性【好用】
【只不过在书写过程中有很多好用的扩展功能】