目录
前言
其实学到了这里,Spring的基础操作学的已经差不多了,但是仅仅这些还不够,我们还需要更重要的知识,为什么呢?我们后端的处理其实就是两个部分
1.后端程序
2.数据库
之前我们就学过了JDBC,但是远远匹配不上我们的Spring框架,所以MyBatis横空出世,接下来一步一步来,从0到基础的掌握,一点点的来。
这里注意了嗷!!重要部分!!!红色写!!!绿色部分属于我的特别声明
一丶关于MyBatis你要知道的事情
<1>既然有了JDBC,我们为什么要学Mybatis?
既然说到了JDBC,那么我们肯定是要梳理一下JDBC的处理过程的
1. 创建数据库连接池 DataSource
2. 通过 DataSource 获取数据库连接 Connection
3. 编写要执行带 ? 占位符的 SQL 语句
4. 通过 Connection 及 SQL 创建操作命令对象 Statement
5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
6. 使用 Statement 执行 SQL 语句
7. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
8. 处理结果集
9. 释放资源
是不是感觉好长好长?
那么我们直接实际来一下,这样体现的更直观。来给你一个使用场景,如果说此时我们有一个数据库存着一个书城里面书的信息,然后此时我们写JDBC怎么写的呢?
然后这个时候你想要增加书籍信息,删除书籍信息,修改书籍信息,你怎么办呢?是不是就是要开始写对应的方法了?这里我们就以增加一本书籍信息为例
这仅仅是增加一本书,如果我们涉及到其他的功能,一个功能一个类,而且如果还涉及到了更为复杂的查询功能,那后面的代码量无疑可想而知。
所以我就单单从上面这段代码来说,JDBC不方便的地方1.JDBC操作步骤有点多
2.JDBC需要替换占位符,需要一个个的调用setXXX(占位符的位置,要替换的值),所以用起来很不爽,太麻烦了
3.如果是查询功能,你需要一个个的调用resultSet.getXXX(结果集字段名)来获取数据,然后再调用对象.setXXX来保存到对象属性中一起处理返回,需要通过这种方式来处理结果集,还是很麻烦。
4.你还需要手动的释放资源和处理异常所以综上,我们要使用Mybatis,那么你说了JDBC不便之处,那Mybiatis方便在哪里呢?
<2>为什么Mybatis简化了JDBC工作?关于ORM框架的略述
什么是ORM呢?这里大概说一下
ORM:对象关系映射,在面向对象编程中,把关系型数据库中的数据与对象建立起映射关系,进而自动的完成数据与对象的互相转化。(JAVA对象模型 <==> 数据库表模型)
那么使用ORM框架有啥好处呢?
所以,作为ORM框架之一的Mybatis,自然而然也就是我们要学习的对象。
二丶搞人心态的Mybatis配置开发过程
<1>配置:创建SpringBoot项目+添加依赖
1>如果你是重新创建,就很简单
那这里就很简单啦,就是在你新创建SpringBoot的时候
勾上就好。
2>关于另类创建项目使用Mybatis,你必须掌握的一种方式
(1)创建maven项目引入依赖
这种方式挺值得学习的,就是你以后的项目,直接创建项目其实挺少的。更多的时候是你要用什么,就去配置什么
特别注意我这里的流程
然后就是添加我们的依赖
此时先在maven仓库上面找对应的依赖
上面是先添加的我们的数据源,然后依法炮制加其他两个
(2)写启动类–注意你自己的包路径
(3)配置连接字符串和xml文件
这里的话其他部分目前固定不变,然后我用红框框起来的部分,就根据自己的配置来。
3>创建实体类和xml文件
本来这一部分应该是属于下一部分的,但是我想了想,它虽然算在处理流程里面,但是实际上把他放在配置里面更好理解。
然后下面是xml文件的书写,也就是我们的sql语句处理
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mapper.UserMapper">
</mapper>
<2>开发:MyBatis框架处理业务的流程梳理
1>设计Controller:接收请求和返回响应
首先你需要能够接收和返回这个前端的请求,所以你需要Controller
2>设计Service:用来做逻辑业务处理
这里其实就是你在Controller里面调用的方法
3>写接口:在类加载路径中查找xml文件
这一部分就是重中之重!!!!
然后这里的话,我特别要说明一下一下
口述一下吧!
这里的话,我就直接从Bean对象的使用开始了,前面我就不说了。
<1>首先Controller来接收请求,然后通过调用UserService这个类对象里面包含的方法去处理我当前的请求
然后可以看到,这里通过调用接口中的方法来进行处理。
<2>那么这里就是重点来了!!!
1.在mybatis启动的时候,当前的mapper接口就通过类的全限定修饰名(全包名.全接口名)产生了一个“命名空间”,此时xml文件中也需要一个配置相同的“命名空间”。
2.然后userMapper接口在执行其方法的时候,他就会去我们之前在类加载路径下的xml文件去查找对应的命名空间
3.查找什么呢?查找与方法名相同的xml语句,也就是sql语句去执行我们对应的流程。
<3>执行完毕之后,把你该返回的数据进行返回。
三丶MyBatis的基础使用–熟悉mybatis流程的话这部分直接跳过吧
我为啥说直接跳过呢?因为这部分主要就是练习代码,你会个基础的增删改查,这部分都能写下来,所以我这里就直接粘贴的截图,有特别的涉及到别的语法的部分,我都用小tips点出来了
<1>增
增加数据这里,算是我们最最基础的功能,
这里我们的占位符用的就很巧:#{对应属性名}
<2>删
和上面差多一样,会SQL基础语句你就能搞
然后再次启动postman
然后就可以看到删除成功
<3>改
直接上截图
然后启动postman,并且查看结果
最后再次查看数据库,修改成功
小tip:关于自增主键的使用–真的不是水字数呀
其实写上面的语句的时候,笔者真不知道该咋写了,处理流程上面已经说完了,然后具体的好像也没啥了,我要在这里写基础的增删改查的SQL语句怎么写嘛?
好像也不至于哈。所以这里我就增加了这个部分。
首先说一下为什么会有这个部分,看下面这个场景
如果是新增功能,那么就很没啥要说,就是一个很简单的增加功能,但是为什么我要写这个呢?原因就是在这个增加之后的返回值,我们如果说想要拿到这个返回值然后去做点事情,那是不是就没有办法?为什么呢?
因为此时我们在操作成功后,返回的是当前我们操作成功了几个数据库数据,比如说我们新增一个用户返回的就是1,它不是我们的id字段,然后此时我们就可以去设置自增主键,达到我们这样的效果
看一看插入成功后的显示
所以为了解决上面这种情况,我们就可以使用自增主键
小tip:查-单表简单查询:resultMap的使用
查询其实应该算进阶,但是我把这部分放在基础里面,操作确实和语法没有涉及到太大的复杂度,特殊的点就在于对于多个对象的处理,还有就是涉及到了resultMap的使用
这里selectAll中,就调用了resultMap,把数据库里面的属性转化为一个个对象进行返回
> 然后进行一下流程的梳理
当然,你也可以进行单个查询,也是用同样的语句,但是这个语句就要改改了
四丶MyBatis进阶使用(查询详解)
我这里,就可以大值说一下部分的细节了。
<1>关于参数占位符 #{} 和 ${}的区别和使用场景
#{}:预编译处理,是指MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使用 PreparedStatement 的 set 方法来赋值。
${}:字符直接替换:是MyBatis 在处理 时,就是把{} 替换成变量的值
1>关于两者的解析过程
#{}可以实现预编译,其实主要表现在数据类型检查和安全检查两部分:
数据类型检查表现在:若检测到为数值类型,就不加引号,即?;若检测到字符串类型,就加上引号,即’?'。
安全检查表现在:若变量的值带有引号,会对引号进行转义处理,这样可以防止sql注入。
$符号主要用于传入的参数是sql片段的场景下,会直接进行字符串替换,完成了sql的拼接。
其实上面已经说了#{}和 $ {}运算符的流程是什么,但是有点空洞,这里再用实例来演示一下
关于${}这里是要特别注意
然后我们写一个例子来验证一下,这里是关于${}的
执行完毕之后,结果如下
但是这里有问题,看下面
2>使用场景
关于#符号:
需要在sql映射文件中动态拼接sql时的开发场景,比如传入多个变量进行条件查询、传入一个POJO进行数据插入等。
关于${}符号符号:
主要用于传入的参数是sql片段的场景下,比如我们不在sql映射文件中利用mybatis的动态sql来拼接sql,而是在java代码中去动态的拼接sql,然后将拼接的sql片段作为变量传入sql映射文件。上面也说了该符号只是进行字符串的替换,如果我们传入一个sql片段的话,相当于直接进行了sql拼接,就不用在sql映射文件中利用mybatis提供的动态sql标签来拼接sql了。
3>关于$符号的sql注入问题
用该符号时要特别注意sql注入的风险,如果该sql片段是根据用户的输入拼接的,要注意检查sql注入的问题,防止数据的泄露与丢失。主要原因上面也说了,${}符号运行流程是字符串的替换,所以注入的时候一定要特别小心使用场景。
<2>like 查询与 concat() 函数使用
什么意思呢?我们看下面
然后结果如下:
我这里主要是点一下,你是用like函数的时候,以前的写法就是不对的,这里我们要搭配函数concat()来实现我们对应的功能
<3>多表查询
这个就是重点了,但是在正式开始书写和梳理流程之前,有一些概念我觉得我应该在这里讲清楚。
没太理解我意思?那我用语言阐述一下
首先,你使用不使用多表查询,或者是映射,或者是其他的,都取决于你当前的对象是否能满足你的需求,我们上面的所有返回方式,都是使用一个对象,然后把要返回的值当做是我们对象的属性,然后返回该对象,但是这里如果你涉及到了当前对象没有的属性的时候,也就是一个对象满足不了多表查询的结果,这就引出了我们接下来的内容
1>实体类中添加属性
看如下使用场景,此时类里面属性如下
但是需求如下
添加字段
此时我们是一个用户绑定了一个时间和一个count数值数,这是单表操作,如果有其他属性的话我们的应对
2>重点:使用映射
然后演示一下吧,关于下面的使用场景
具体怎么映射呢?一句话来说一下
转换为JAVA对象,并且对象之间建立联系,一对一或者一对多
(1)一对多映射–User为主题
首先看我们下面的图
这就是一对多的思想,此时在User类里面建立文章类的属性
写完之后,我们是不是就可以建立从用户结果集到映射,一个用户关联多个文章?
然后是处理接口
是不是有点看不清呢?笔者尝试用阅读模式看了一下,那还是把两个部分的截图放大下,看的清晰些
最最主要的是什么呢?就是我们的处理流程,而处理流程中的重点就是在一个ResultMap
映射中有着另一个映射来进行我们关系的转化,也就是实现一对多的关系。
然后通过浏览器访问查看返回数据
(1)一对一映射–Article为主题
其实和上面有点类似,但是这次我们的xml路径不再是原来User的路径了
这里我就省略Controller和Service和接口的处理了,和我们之前写的一样,但是主要是什么呢?就是注意它这里的处理流程和我们上面的一对多是一样的
然后通过浏览器查看返回数据
<4>动态SQL使用
这里的话,还是使用的我们的SQL语句,但是主要就是在书写格式上面需要注意一下,所以这里笔者就不分模块了,直接一网打尽
<1> < if>标签
在注册用户的时候,可能会有这样一个问题,必填字段和非必填字段。后端如果判断当前传入字段是必填还是非必填呢?
然后发起请求进行响应查看
<2> < trim>标签
演示一:
演示二:
在以上 sql 动态解析时,会将第一个 部分做如下处理:
基于prefix 配置
,开始部分加上 (
基于suffix 配置
,结束部分加上 )
多个 组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于suffixOverrides 配置
去掉最后一个 ,
注意<if test=“createTime != null”> 中的 createTime 是传入对象的属性
<3>< where>标签
传入的用户对象,根据属性做where条件查询,用户对象中属性不为 null 的,都为查询条件。如 user.username 为 “a”,则查询条件为 where username=“a”:
UserMapper 接口中新增条件查询方法:List<User> selectByCondition(User user);
以上标签也可以使用<trim prefix="where" prefixOverrides="and">
替换。
<4>< set>标签
根据传入的用户对象属性来更新用户数据,可以使用标签来指定动态内容。
UserMapper 接口中修改用户方法:根据传入的用户 id 属性,修改其他不为 null 的属性
<5>< foreach>标签
对集合进行遍历时可以使用该标签。标签有如下属性:
collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
item:遍历时的每一个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串