SSM(B站黑马)学习笔记
01-1-Spring概述
01-2-Spring IOC
01-3-Spring AOP
01-4-Spring 事务
02-SpringMVC
03-SSM整合
04-Maven高级
05-SpringBoot
06-MyBatisPlus
文章目录
- SSM(B站黑马)学习笔记
- 前言
- 05MyBatisPlus
- MyBatisPlus简介
- 入门案例
- 基于SpringBoot使用MyBatisPlus
- 细节处理
- MyBatisPlus概述
- 标准数据层开发
- 标准CRUD制作
- Lombok插件
- 标准分页功能制作
- 使用分页查询selectPage
- 配置分页拦截器
- 开启MP日志打印sql语句
- DQL(查询语句)编程控制
- 条件查询方式
- 环境准备
- 日志处理
- 构建条件查询 wrapper
- 多条件构建
- 条件查询—null值处理
- 查询投影(查询字段控制)
- 查询条件设定
- 映射匹配兼容性
- DML(增删改)编程控制
- id生成策略控制
- 多数据操作(删除与查询)
- 逻辑删除
- 乐观锁
- 思路分析
- 实现步骤
- 代码生成器
- 原理分析
- 代码生成器实现
- 注:
前言
SSM(B站黑马)学习笔记 06-MyBatisPlus
05MyBatisPlus
MyBatisPlus简介
入门案例
-
MyBtaisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率
-
开发方式
- 基于MyBatis使用MyBatisPlus
- 基于Spring使用MyBtaisPlus
- 基于SpringBoot使用MyBatisPlus
基于SpringBoot使用MyBatisPlus
环境准备—数据库表
创建Springboot工程
由于idea没有收录MyBatisPlus的起步依赖所以只选择数据库驱动,新建后手动导入MP的起步依赖
导入依赖
MP起步依赖&druid
注意:MyBatisPlus起步依赖已经包括了MyBatis依赖和与spring整合的依赖,无需重复导入免得依赖冲突
如果不使用druid也行,用的就是默认内置数据源,可以更改为阿里巴巴的druid数据源
配置数据源信息和新建pojo实体类 注意:是Long而不是long
编写dao层
没错,只需要继承BaseMapper再加泛型就把sql语句写好了!!
测试
dao接口里只继承了一个东西还什么都没写就已经有很多方法了,这就是MyBatisPlus帮我们做的
细节处理
这里的泛型也代表着你要使用的表名,如果表名是mp_user这种,那么你需要使用驼峰命名法去写泛型。不然会报如下错误。或者用注解进行匹配 下方映射匹配兼容性有讲解
如果测试运行出现如下错误,在设置里勾选相关配置即可
网络上查阅,得到的解释说IDEA的Build(编译)操作和Maven的Build是分开的,并不是一回事,所以直接将其统一交给maven进行管理,通过setting->maven->Runner,勾选:Delegate ide build/run actions to Maven,再次运行就不会再出现这样的问题了。就是将服务构建/启动的任务交给maven去解决。勾选SkipTests为了防止插入时出现两条一模一样的数据。其他版本IDEA启动该版本时,并没有出现,只有2020.1版本的idea启动报了该问题;
MyBatisPlus概述
- MyBtaisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率
- 官网:https://baomidou/(苞米豆,国人开发的)
官方文档中有这样一幅图可以看出MP旨在成为MyBatis的最好搭档,而不是替换MyBatis,所以可以理解为MP是MyBatis的一套增强工具,它是在MyBatis的基础上进行开发的,我们虽然使用MP但是底层依然是MyBatis的东西,也就是说我们也可以在MP中写MyBatis的内容。
MyBatisPlus特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 强大的CRUD操作:内置通用 Mapper,少量配置即可实现单表大部分 CRUD 操作
- 支持Lambda:编写查询条件无需担心字段写错
- 支持主键自动生成
- 内置分页插件
- …(详见官方文档)
标准数据层开发
标准CRUD制作
- CRUD说的就是增查改删
- C:创建(Create)
- R:查找(Retrieve)
- U:更改(Update)
- D:删除(Delete)
增
删 Long类型要加L
改
提交什么就修改什么,没修过就不动,原先手写没修改的地方会变null
查
Lombok插件
导入依赖
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
下载插件,也可以不下载但使用set和get方法会一直爆红不影响运行
使用前
使用后
使用注解代替原先手写的get set等方法
一个@Data顶前面全部,但不包括构造方法
标准分页功能制作
selectPage源码
需要一个page对象,而这个page对象是查询条件并且是IPage的实现类
使用分页查询selectPage
配置查询条件,发现查询结构并没有分页,原因是MyBatisPlus给我们提供了一个分页拦截器,如果不配置就无法使用分页功能。
配置分页拦截器
记得进行加载,两种方法 1.配置类添加@Configuration 2.启动类使用@Import
查询使用分页查询 成功分页
开启MP日志打印sql语句
查询其sql语句 使用日志打印 (一般不出问题不开)
DQL(查询语句)编程控制
条件查询方式
- MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合
这个我们在前面都有见过,比如查询所有和分页查询的时候,都有看到过一个Wrapper
类,这个类就是用来构建查询条件的,只是前面都没配置条件所以都设为null了。如下图:
环境准备
日志处理
在执行例如查询的操作时,控制台会出现一大堆日志信息,太占篇幅了,而且对我们来说意义不大。如图
处理:配置一个空的logback.xml文件即可
关闭springboot和mybatisplus的启动图标
构建条件查询 wrapper
通过观察源码可知,在进行条件查询时,我们构建条件是在Wrapper这个类上,因为它是一个抽象类,所以我们需要去找到它对应实现的继承子类,关于实现类也有很多,说明我们有多种构建查询条件对象的方式
注:抽象类必须被继承,才能被使用 详见:Java抽象类 | 菜鸟教程
1.第一种:QueryWrapper
2.第二种:QueryWrapper的基础上使用lambda
写条件的时候,容易出错,比如age写错,就会导致查询不成功。为防止这种情况,使用lambda格式
记得指定泛型
MpUser::getAget,为lambda表达式中的,类名::方法名
3.第三种:LambdaQueryWrapper
直接返回Lambda格式的QueryWrapper对象,就不用写 .lambda 了
多条件构建
查询数据库表中,年龄在10岁到30岁之间的用户信息
可以支持链式编程
查询数据库表中,年龄小于10或年龄大于30的数据
条件查询—null值处理
我们在做条件查询的时候,一般会有很多条件可以供用户进行选择查询。例如价格筛选时,后台在做价格查询的时候,一般会让 price>值1 and price <值2。如果前端没有输入值2,后台也没处理就会出现 price>8000 and price < null问题。最后的结果无法正常显示。
案例:查询数据库表中,根据输入年龄范围来查询符合条件的记录
用户输入值:
只输入第一个框,说明要查询大于该年龄的用户
只输入第二个框,说明要查询小于该年龄的用户
两个框都输入了,说明要查询年龄在两个范围之间的用户
环境准备
如何接收前端的两个数据?
我们可以使用两个简单数据类型,也可以使用一个模型类,但是User类中目前只有一个age属性,如:
使用一个age属性,如何去接收页面上的两个值呢?这个时候我们有两个解决方案
方案一:添加属性age2,这种做法可以但是会影响到原模型类的属性内容
方案二:新建一个模型类,让其继承User类,并在其中添加age2属性,UserQuery在拥有User属性后同时添加了age2属性。
实现null处理
处理前,存在null值查询为空
原始null处理 存在问题:如果条件多的话,每个条件都需要判断,代码量就比较大
MP给我们提供的简化方式
.lt 或 .gt方法
condition为boolean类型,返回true,则添加条件,返回false则不添加条件
查询投影(查询字段控制)
注:MP不影响mybatis框架,有些语句不支持还是要手写mybatis代码
查询出指定字段的数据
聚合查询
count:总记录数
max:最大值
min:最小值
avg:平均值
sum:求和
使用原始SelectList()方法,查询结果为null,原因是查询结果封装在User对象里,count等的结果没地方放如图
MP为我们提供了专门的查询操作 selectMaps
查询条件设定
更多查询条件设置参考文档:https://baomidou/pages/10c804/#abstractwrapper
等值查询
eq(): 相当于 =
selectList:查询结果为多个或者单个
selectOne:查询结果为单个
范围查询
- gt(): 大于(>)
- ge(): 大于等于(>=)
- lt(): 小于(<)
- lte(): 小于等于(<=)
- between(): between ? and ?
模糊查询
- like():前后加百分号,如 %J%
- likeLeft():前面加百分号,如 %J
- likeRight():后面加百分号,如 J%
映射匹配兼容性
问题一:表字段与编码属性不同步
处理办法
问题二:编码中添加了数据库未定义的属性
处理办法
问题三:采用默认查询开放了更多的字段查看权限
处理办法
问题四:表名与编码开发设计不同步
处理办法
DML(增删改)编程控制
id生成策略控制
- 不同的表应用不同的id生成策略
- 日志:自增(1,2,3,4,…)
- 购物订单:特殊规则(FQ23948AK3843)
- 外卖单:关联地区日期等信息(10 04 20220816 34 91)
- 关系表:可省略id
- …
环境准备
id自增策略
IdType.AUTO 使用数据库自增
IdType.INPUT 用户输入ID
若用户没输入且数据库没开启自增则报错(没开启用户输入没自增也会报错-.-)
注:以下几种类型、只有当插入对象ID 为空,才自动填充。
IdType.ASSIGN_ID 雪花算法生成ID
雪花算法(了解)
简化配置
模型类主键策略设置
如果每一个模型类上都需要使用相同的生成策略,如:
一个个写太麻烦了,在配置文件中进行全局设置进行处理
mybatis-plus:
global-config:
db-config:
id-type: assign_id
配置完成后,每个模型类的主键ID策略都将成为assign_id
数据库表与模型类的映射关系
MP会默认将模型类的类名名首字母小写作为表名使用,假如数据库表的名称都以tbl_
开头,那么我们就需要将所有的模型类上添加@TableName
,如:
配置起来还是比较繁琐,简化方式为在配置文件中配置如下内容:
mybatis-plus:
global-config:
db-config:
table-prefix: tbl_
设置表的前缀内容,这样MP就会拿 tbl_
加上模型类的首字母小写,就刚好组装成数据库的表名
多数据操作(删除与查询)
多条数据同时删除,例如勾选购物车全部
删除前
使用.deleteBatchIds()方法删除多条
MP同样支持按多id查询
.selectBatchIds()方法
逻辑删除
场景介绍:销售部门销售产品对应合同表和员工表,一个员工可以签多个合同 如下图:
假如员工1离职了,那么对应的数据也要删除。设计表时合同表与员工表存在主外键关系,删除员工信息也得把合同表的前三条删除。
存在问题:年终核算时,因为员工离职,合同信息也跟着删除了,结算金额就会对不上
- 我们日常的删除操作对业务有伤害性,业务数据从数据库中丢弃。
- 逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留才数据库中。
简单来说就是让数据做了个标记在逻辑上表示删除而不是物理删除 如图:
MP为我们提供了强大的功能,自动帮我们实现逻辑删除
1.修改数据库
增加deleted字段,表示逻辑删除 约定默认0未删除 1删除
2.实体类添加属性 并设置为逻辑删除
3.测试
直接使用MP的删除方法,指定逻辑删除字段后会自动实现逻辑删除,执行的sql语句时update而不是delete
注意:开启逻辑删除后会对MP的查询有影响,执行的sql语句会多一个查询条件 如:
在MP的认知中标记为1的就是删过的。如果要查询全部得自己写sql语句
全局设置 简化开发
逻辑删除的操作可能会有大量的需求,每个地方写太繁琐了,可用配置全局设置统一处理
mybatis-plus:
global-config:
db-config:
# 逻辑删除字段名
logic-delete-field: deleted
# 逻辑删除字面值:未删除为0
logic-not-delete-value: 0
# 逻辑删除字面值:删除为1
logic-delete-value: 1
乐观锁
锁一般处理的是并发问题
- 业务并发现象带来的问题:秒杀
- 假如有100个商品或者票在出售,为了能保证每个商品或者票只能被一个人购买,如何保证不会出现超买或者重复卖
- 对于这一类问题,其实有很多的解决方案可以使用
- 第一个最先想到的就是锁,锁在一台服务器中是可以解决的,但是如果在多台服务器下锁就没有办法控制,比如12306有两台服务器在进行卖票,在两台服务器上都添加锁的话,那也有可能会导致在同一时刻有两个线程在进行卖票,还是会出现并发问题
- 我们接下来介绍的这种方式是针对于小型企业的解决方案,因为数据库本身的性能就是个瓶颈,如果对其并发量超过2000以上的就需要考虑其他的解决方案了。
简单来说,乐观锁主要解决的问题是当要更新一条记录的时候,希望这条记录没有被别人更新。
乐观锁就是一种思想,通过sql语句实现
思路分析
数据库表中添加version列,比如默认值给1
第一个用户要修改数据前,先查询数据,获取version=1
第二给用户要修改数据前,先查询数据,获取version=1
当第一个用户执行更新操作时,执行sql语句为:
update set abc = ***, version = version + 1 where id = * AND version = 1
当第二个用户执行更新操作时,执行sql语句为:
update set abc = ***, version = version + 1 where id = * AND version = 1
最终成功执行更新操作的是第一个用户,因为用户1和用户2查询出来的version都是1,但用户1执行更新操作不仅修改了其它字段还把version值+1了,等到用户2再执行更新操作version变成2了无法满足version = 1条件,所以用户1成功修改,用户2修改失败。假如用户2先执行更新操作则先满足version = 1条件并将version+1
version在成功执行一次修改后都会+1,不管谁先执行都会确保只能有一个线程更新数据,这就是MP提供的乐观锁的实现原理分析
实现步骤
1.数据库添加字段 version 默认为1
2.实体类添加属性 并设置为乐观锁
3.添加乐观锁的拦截器
就像分页拦截器帮我们添加 limit ?,? 乐观锁拦截器就是帮我们添加version = version + 1的
4.测试
发现乐观锁拦截器没有运行,原因是操作使用乐观锁时必须提供定义的乐观锁字段 version值
提供version值后 它会根据提供的值进行判定 最后修改+1。 所以没有提供version就不运行这个机制
存在问题:version必须收集提供,如果不是通过手动收集提供怎么设置version值
解决办法:先通过要修改的id将当条数据查询出来返回给user对象,再将修改的属性逐一设置进去。这样对象里就有version值,就不用手动提供了
秒杀模拟
多人修改同一条数据,只能有一人修改成功
用户1和用户2 同时拿到id为3的数据,但用户2先将数据修改,version+1导致用户1判断version=3失败,结果为用户2秒杀(修改成功)
代码生成器
原理分析
例如: 正 呢。
我们可用在空白处进行填空形成完整的句子
农民伯伯 正 忙着插秧 呢 / 警察叔叔 正 指挥交通 呢
而我们平时写的代码其中有很多重复内容,只要修改对应的东西就能生成一个全新的类 如:
再复杂一点的,比如实体类,相关字段我们可用从数据库读取,其形式也比较固定。把它挖空后我们就得到一个模板
几乎所有的类都可以这样做,所以MP就帮我们做了一个代码生成器
- 模板:MyBatisPlus提供 (可自定义,但麻烦,不建议)
- 数据库相关配置:读取数据库获取信息
- 开发者自定义配置:手工配置 (像id生成策略这些需要手工配置)
代码生成器实现
环境准备
新建springboot工程 勾选相关起步依赖
导入相关依赖
mybatisplus代码生成要用一套模板,模板技术是一个独立的技术,在MP里默认使用的是velocity
<dependencies>
<!--MyBaisPlus-springboot-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--velocity模板引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
项目结构
都是空的,只导入了依赖 其它什么都没改
1.创建代码生成类
2.创建代码生成器对象,配置,执行代码生成器
注意:这里手动new数据源对象,是因为这只是个代码生成器,只运行一次就不用了,不用考虑耦合
执行代码生成器后它就会根据连接的数据库生成对应的类,由于没有指定生成位置,所以会默认在D盘生成
配置更多详细的信息可以对类和包的形成更精准,如下:
生成结果
MP帮我们把业务层的一些基础的增删改查也都实现了,可以直接进行使用。但我们一般不使用,因为业务层代码是根据项目进行编写的,不只是简单的增删改查。对要使用的保留,不使用的删除
总结:通过预设的模板,加配置自动生成代码。前期学习先不要用这个,到实际开发在使用
注:
该内容是根据B站黑马程序员学习时所记,相关资料可在B站查询:黑马程序员2022最新SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术
更多推荐
【SSM学习】06-MyBatisPlus
发布评论