文章目录
- 一、什么是MyBatis?
- 1.2、JDBC
- 二、使用Mybatis
- 2.1、配置MyBatis开发环境
- 2.1.1、配置连接字符串
- 2.1.2、配置MyBatis中的XML路径
- 2.2、使用MyBatis模式和语法操作数据库
- 三、使用 Mybatis 进行增删改查操作的要点
- 3.1、ResultMap的用法
- 四、Mybatis操作难点
- 4.1、#{ } 和 ${ } 的区别
- 4.1.1、SQL注入问题
- 4.2、like 模糊查询
- 4.3、多表查询、联合查询
- 4.3、动态 sql 的使用
- 4.3.1、if 标签
- 4.3.2、trim 标签
- 4.3.3、where 标签
- 4.3.4、set 标签
- 4.3.5、foreach 标签
一、什么是MyBatis?
MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程(多条SQL语句的集合)以及高级映射。MyBatis 去除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO (Plain Old Java Objects,普通老式Java对象)为数据库中的记录。
存储过程:
高级映射:程序中的类对应数据库中的表,程序中的类里的属性对应数据库的表中的字段。ORM把数据库映射为对象:数据库表(table) -->类(class)、
记录(record, 行数据) -->对象(object)、字段(field) -->对象的属性(attribute)
简单来说MyBatis是更简单完成程序和数据库交互的工具,也就是更简单的操作和读取数据库工具。
1.2、JDBC
我们之前使用JDBC连接数据库,那为什么还要学习MyBatis?这是因为JDBC操作十分繁琐。以下是JDBC的操作流程:
(1)、创建数据库连接池DataSource
(2)、通过DataSource获取数据库连接Connection
(3)、编写要执行带 ?占位符的SQL语句
(4)、通过Connection及SQL创建操作命令对象Statement
(5)、替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
(6)、使用Statement执行SQL语句
(7)、查询操作:返回结果集ResultSet,更新操作:返回更新的数量
(8)、处理结果集
(9)、释放资源
JDBC代码例子的链接
二、使用Mybatis
学会使用Mybatis需要掌握两个步骤:
2.1、配置MyBatis开发环境
在项目中添加MyBatis:
注意:框架 framework 和 框架 Driver 必须成对出现。
当项目中添加了数据库框架后,启动项目是失败的也不要慌张,这是正常现象。
因为项目中添加了数据库框架之后,却没有配置数据库的路径,所以项目启动报错。(一台机器上可以安装很多个数据库,想要连接哪个数据库就需要指定那个数据库的路径,才能够连接成功。)
2.1.1、配置连接字符串
那怎么指定呢??此时就需要配置连接字符串和MyBatis。需要进行两项设置,数据库连接字符串设置和MyBatis的XML文件配置。
(1)、配置连接字符串(4项)
如果是application.yml配置文件,则添加如下内容(系统配置项):(给的是模板,具体内容以自己的数据库为准)
#数据库连接配置
spring:datasource:url: jdbc :mysql://localhost:3306/mycnblogcharacterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
2.1.2、配置MyBatis中的XML路径
MyBatis中有两种实现数据库增删改查的方式,分别是:1、使用 XML 的范式。2、一种是使用注解的方式。
虽然使用注解的方式来写sql语句去实现数据库的增删改查功能一开始会比较容易,但是这是假象,只适合简单的sql语句以及简单的功能,但是当业务复杂起来的时候,使用注解的方式就十分不方便,同时使用注解的方式还容易将代码与sql语句混杂在一起,不容易实现代码的复用性、简洁性。因此我们通常会使用XML文件来实现数据库的增删改查。
只放个注解的例子图,不推荐使用这种方式,现在很少有人用了。
这是使用XML的方式:
因为Mybatis由2部分组成:
1、接口 ( interface ) :接口里会声明所有操作方法。这些方法是给程序里的其他类来调用。
2、使用 XML 实现接口。即XML里需要写具体的SQL语句。
想要使用 XML 的方式实现数据库的增删改查,还需要在配置文件中配置如下内容:(这些配置信息是告诉Mybatis要使用哪些文件)
#设置mybatis的xml保存路径
mybatis:mapper-locations: classpath:mapper/*Mapper.xml
2.2、使用MyBatis模式和语法操作数据库
这一步就是遵循MyBatis的写法在项目中构建相应的业务实现即可。
项目的业务交互图:
此处是一个项目例子来使用MyBatis模式和语法操作数据库:
一、基础准备
(1)、首先需要创建一个ssm的项目,项目需要准备好Mybatis Framework以及 MySQL Driver ,创建好后将配置文件中的配置信息先配置好:
(2)、然后在项目中依次创建好 controller层(控制器层)、service层(服务层)、mapper层(数据库持久层)、entity层(实体类)。
(3)、然后需要准备一个数据库,数据库中含有一张表,将表与程序中的类映射起来。
二、构建 Mapper 层的代码实现
(1)、在mapper层定义一个接口:
接口中可以含有多个方法,这些方法就对应你项目的增删改查或者其他的功能模块。
(2)、创建 XML 实现
在mapper包下创建一个 xml 文件:
三、实现服务层代码
四、实现控制器层代码
写完代码后,启动项目,在浏览器上输入URL,获取数据库中的数据:
三、使用 Mybatis 进行增删改查操作的要点
(1)、使用Mybatis进行查询操作
查询操作的两个必备属性中,第一个属性是id;第二个属性写法可以是 ResultType,也可以是 ResultMap。
使用ResultType,是因为程序中的实体类里的属性名称都和数据库中表的字段名称一致,所以可以使用ResultType。
使用ResultMap,是因为一般在公司,数据库是专门由DB负责的,而程序代码的书写由程序员负责,一般开始项目大家都是同时开工,程序员不知道DB设计出的数据库里面会用什么表名、字段名,因此此时想要让程序与表映射,需要用到ResultMap。(即ResultMap 用在当程序中的属性名与数据库表中的字段名不一致时)。
举个例子:
这是因为在查询的过程中,如果数据库表的字段名能够与程序中的属性名对应上,那就将数据库中的数据赋值给程序中的属性,如果数据库表中的字段名和程序中的属性名对应不上,那程序中的属性值就是null。
插入、删除、修改操作时也有这样的情况,但是和查询时相反的。若程序中的属性名与数据库表中的字段名匹配,可以赋值,操作成功,否则反之。
ResultMap(返回字典映射) 应用场景:
(1)、字段名称和程序中的属性名不同的情况,可使用resultMap配置映射;
(2)、一对一和一对多关系可以使用resultMap映射并查询数据。
3.1、ResultMap的用法
(1)、先声明
(2)、再使用
除了使用 resultMap 的方法,还有另一种更加简单的方法:
使用数据库别名 as 重命名。
(2)、使用Mybatis进行添加操作
因为我们的IDEA是默认隐藏Mybatis生成sql的执行细节,因此如果想要让控制台打印我们所执行的sql语句,可以在配置文件中进行配置。配置后,可利用sql语句排查问题。
配置文件:
(3)、使用Mybatis进行删除操作
(4)、使用Mybatis进行修改操作
Mybatis项目例子,这个链接是上面所写的项目例子与数据库所进行的增删改查的操作的具体代码,大家可以跟着动手写一写,熟能生巧。
四、Mybatis操作难点
前面在项目例子中演示的增删改查操作,是最基本最简单的操作,但其实在实际项目中,远比这些难得多,不仅仅涉及到对一个表的增删改查,还会涉及到多表查询操作、联合查询、条件查询…这个时候的sql语句就会比较难了。
4.1、#{ } 和 ${ } 的区别
在.xml文件里书写sql语句时,其实我们一般见到的都是 #{ } 类型的:
但是其实 ${ } 也可以实现和 #{ } 一样的功能,但是为什么现在常见的都是使用#{ },而 ${ }却很少见呢?他们有什么区别?
#{ } 的sql语句时使用的是预编译处理,即sql语句中先使用占位符?。这样的好处就是先占了才赋值,可以适配多种情况,不管是整型还是字符串…
而 ${ } 的sql语句是直接赋值,直接赋值的话整型的情况下没有问题,但是字符串的情况下就会有问题:
但是,${ } 有一个 #{ }不具备的重要功能:能够传递一些关键字。(但是在使用 ${ } 传递关键字时,我们还必须确定这个传递的值能够穷举:就是需要先在 controller 层对这个值进行参数校验,比如传的是一个order值,这个order变量它的取值是否是desc或者asc,如果都不是,不给传值,避免 ${ } 的sql注入问题)
代码实现:
单元测试:
4.1.1、SQL注入问题
我们上面说了,传关键字是 ${ } 的唯一应用场景(是因为 ${ } 不安全,会产生SQL注入的问题)。但是我们必须保证传的这个参数是可预期的,如果传的是一个不可预期的参数,有可能会产生SQL注入的问题:因为 ${ } 是直接赋值,因此一些有心人会抓住这个漏洞做一些非法的事情。
譬如:当我们进行登陆操作时,当使用 ${ } 进行登陆操作的sql语句书写时(要想测试sql注入现象成功,需要保证数据库里只有一行记录的情况下才可以):
单元测试1:
单元测试2(sql注入问题):
但是使用 #{ } 就没有sql注入这样的问题:
那么为什么这样一串字符串:’ or 1='1 就会引起sql注入问题?
总结:#{ } 和 ${ } 的区别:
(1)、 ${ } 存在 sql注入问题,而 #{ } 不存在。
(2)、 ${ } 是直接赋值,而#{ } 是采用预编译的。
使用 ${ } 的注意事项:
(1)、确保传入的值是可穷举,可预期的。
(2)、需要先在 controller 层进行参数校验。
4.2、like 模糊查询
此时可以采用 mysql 的内置函数 concat() 进行拼接:
4.3、多表查询、联合查询
多表查询是非常容易遇到的操作,并且多表查询比单表查询要难。当我们需要进行多表查询,但是实体类却只包含单表查询的实体类,该怎么办??
针对上面的问题,有两个解决方法:
(1)、不再继承基础类,直接写全所有属性:
(2)、仍旧是继承自基础类,但是需要将lombok生成的toString()覆盖
因此我们可以在扩展类中自己写一个 toString() 方法,将lombok自动生成的toString() 方法覆盖掉:
注意:一般我们在写实体类的时候,习惯将类都实现 Serializable 接口并新增一个版本字段。因为我们写的实体类,不可避免后面都会有可能进行序列化/反序列化。
当我们遇到多表联查,直接采用这个解决方案即可:
联表查询语句(left jion / inner join)+XXXVO 解决。
4.3、动态 sql 的使用
动态 sql 是 Mybatis 强大特性之一,能够实现复杂条件下不同的 sql 拼接。
动态sql的应用场景一般在当前界面既含有必填项又含有非必填项,如下图此类:
4.3.1、if 标签
if标签是一个条件判断,如果if标签里的属性test是true,就执行if标签里的内容,如果属性test是false,就不执行if标签里的内容。if标签一般用于含有较少非必填项的场景。
if标签语法:
<if test = "参数名 != null and 参数名 != ''">...
</if>
例子:
使用动态sql时:
4.3.2、trim 标签
trim标签一般用于含有多个非必填项的场景。trim要求里边必须至少包含一个if标签去配合使用!
trim标签的语法:
这两标签一般用于插入操作。
4.3.3、where 标签
where 标签的语法:
4.3.4、set 标签
set 标签语法:
以上标签也可以使用 < trim prefix= “set” suffixoverrides=“,”> < /trim>替换。
单元测试成功:
4.3.5、foreach 标签
foreach标签的应用场景一般是在批量操作上。例如批量删除批量修改批量添加…当系统进行批量操作时,前端传的是一个集合,后端需要对集合进行遍历时就可以使用该标签。
< foreach> 标签有如下属性:
(1)、collection: 绑定方法参数中的集合,如List, Set, Map或数组对象
(2)、item: 遍历时的每一 个对象
(3)、open:语句块开头的字符串
(4)、close: 语句块结束的字符串
(5)、separator:每次遍历之间间隔的字符串
foreach标签语法: