文章目录
1. 如何理解Mybatis?
这里我们先看看什么是ORM
ORM(Object Relational Mapping)
ORM:是对象关系映射
的意思,它是一种思想
,是将数据库中的每一行数据用对象的形式表示
出来
Mybatis
-
Mybatis是一个Java的持久层框架,它的内部封装了JDBC使得开发者只需要关注 sql 语句本身,而不需要去花费精力处理加载驱动、创建连接、创建 statement 等繁杂的过程,
-
Mybatis 采用ORM思想解决实体和数据库映射的问题,简单的说
就是把数据库表和实体类及实体类的属性对应起来
2. 为什么说Mybatis是半自动ORM映射工具?
Mybatis 在查询关联对象时,需要在xml中手动编写sql语句
来完成,所以称之为半自动ORM映射工具
3. JDBC 编程回顾
- 加载驱动:
Class.forName("com.mysql.jdbc.Driver")
- 获取连接:
DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "root")
- 创建
sql
语句,带有占位符
:String sql = "select * from user where username = ?";
- 执行
sql
语句,获取PrepareStatement
对象:ps = conn.prepareStatement(sql);
- 处理结果集:
ps.executeQuery();
- 关闭资源
4. JDBC开发有哪些不足,Mybatis中是如何解决的?
-
频繁创建数据库连接对象、释放容易造成系统资源浪费,影响系统性能
解决方案:在mybatis-config.xml中配置数据库连接池,使用连接池管理数据库连接 -
Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码
解决方案:将sql语句编写在XXXmapper.xml
文件中与java代码分离 -
向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应
解决方案:Mybatis自动将java对象映射至sql语句 -
对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便
解决方案:Mybatis自动将sql执行结果映射至java对象
5. Mybatis的优点和缺点
优点:
- 基于sql语句编程,灵活,不会对应用程序或者数据库的现有设计造成任何影响;sql 写在xml 里,解除sql 与程序代码的耦合,便于统一管理;提供 xml 标签,支持编写动态 sql 语句,并可重用
- 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
- 很好的与各种数据库兼容(底层还是JDBC连接数据库,所以JDBC支持的数据库 Mybatis 都支持)
- 能够与Spring很好的集成
- 提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射
标签,支持对象关系组件维护
缺点:
- 当字段多、关联表多时,sql 语句的编写量较大,要求开发人员编写sql语句的功底要强
- sql 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库
6. Mybatis的编写步骤
- 创建 SqlSessionFactory
- 通过SqlSessionFactory创建SqlSession
- 通过SqlSession来执行数据库的操作
- 调用session.commit()提交事务
- 调用session.close()来关闭会话
7. Mybatis的工作原理
- 读取 Mybatis 配置文件:mybatis-config.xml 为 Mybatis 的全局配置文件,运行环境等信息(eg:连接数据库的配置信息)
- 加载映射文件,即加载 sql 映射文件。该文件中配置了操作数据库的 sql 语句,需要在Mybatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表
<mapper resource = "/xxxMapper.xml"/>
- 构造会话工厂:
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
- 创建会话对象:
sqlSession = sqlSessionFactory.openSession();
- Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护
- MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息
- 输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程
- 输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程
8. #{}和${}的区别
#{}
是占位符,有预编译处理,${}
是拼接符,没有预编译处理- Mybatis 在处理
#{}
时,#{}
传入参数是以字符串传入,会将 sql 中的#{}
替换为?
号,调用PreparedStatement的set方法
来赋值,在处理${}
时,是将原值传入,就是把${}
替换成变量的值,相当于JDBC中的Statement
编译 - 变量替换后,
#{}
对应的变量会自动加上单引号,而${}
对应的变量不会加上单引号 #{}
可以有效的防止SQL注入,提高系统安全性;${}
不能防止SQL 注入
补充: 什么是 sql 注入?
用户提交带有恶意的数据与SQL语句进行字符串方式的拼接
,从而影响了SQL语句的语义,最终产生数据泄露的现象
9. 模糊查询l语句该怎么写?
%${name}%
:这种方式可能会引起 sql 注入,不推荐使用
%#{name}%
:注意:
这里的#{}
解析sql
语句时,会在变量外侧自动加单引号''
,所以这里%需要用双引号,否则无法查找到结果CONCAT('%',#{name},'%')
:使用CONCAT()函数,推荐使用
10. 一级缓存和二级缓存的区别?
1. 一级缓存(本地缓存)
在参数和SQL完全一样的情况下,我们使用同一个SqlSession
对象调用一个Mapper方法
,往往只执行一次SQL
,因为使用SelSession
第一次查询后,MyBatis
会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession
都会取出当前缓存的数据,而不会再次发送SQL
到数据库
- 一级缓存默认是开启的,我们不需要做任何配置
- 指的是
Mybatis
中SqlSession
对象的缓存 - 当
session
关闭或者刷新的时候缓存清空 - 不同
sqlsession
之间缓存互不影响
2. 二级缓冲(全局缓冲)
二级缓存指的就是同一个namespace
下的mapper
,二级缓存中,也有一个map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。
- 二级缓冲默认是没有开启的,需要手动开启
- 二级缓存是 mapper 映射级别的缓存,多个
SqlSession
去操作同一个 Mapper 映射的 sql 语句,多个SqlSession
可以共用二级缓存,二级缓存是跨SqlSession
的 - 可以认为它指的是
Mybatis
中SqlSessionFactory
对象的缓存。由同一个SqlSessionFactory
对象创建的SqlSession
共享其缓存
11. properties(属性)
properties可以对数据源的4个属性进行配置,有2种方式
1. 方式一
在properties标签内配置属性,在dataSource中获取属性值就可以了
2. 方式二
数据库的属性发生改变,我们需要修改配置文件。一般我们会把数据库的配置属性写在一个文件中,放在classpath下。
properties
标签有2个属性,一个是resource
,一个是url
- 这里我们使用的是
resource
:是一个相对classpath
下的路径,所有我们直接写jdbc.properties
就可以了 - 如果使用
url
的话,必须要满足url
的要求才可以。url:uniform resource locator,统一资源定位符
:http:// localhost: 8080 /day01/servlet1/
,分别对应 协议 主机名 端口号 URI,是web中可以唯一定位一个资源的路径
12. typeAliases(别名)
这样的话,在sql
映射文件中,就可以修改resultType
,获取或者parameterType
的值为user
(大小写都可以)了
但是,这里又会发现一个问题,如果实体类比较多时,每一个类都需要设置别名,那么在配置文件中就会写很多的标签,会让配置文件体积变大,所以这里我们还可以通过另一个标签设置别名,只需指定需要设置别名的包即可
解决方案:
12. mappers(映射器)
mappers标签用于指定sql映射文件,这里有三种模式
1. 方式一
- resource:使用相对于类路径的资源,指定sql映射文件的类路径
2. 方式二
3. 方式三
如果在我们的工程中,持久层接口和映射文件比较多的话,就要写很多的mapper,如下图:
所以,我们可以通过下面的方式去指定映射:
这种方式要求:持久层接口的名称和sql映射文件的文件名相同,并且路径相同
13. Mybatis的事务控制
1. Mybatis中事务的提交方式
在 JDBC 中我们可以通过手动方式
将事务的提交改为手动方式,通过setAutoCommit()方法
就可以调整,Mybatis 中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制
以保存用户为例:
执行完方法之后,需要执行再执行destroy方法:
在该方法中,手动提交事务。看一下执行过程:
这是Connection的整个变化过程,通过分析我们能够发现之前的 CUD 操作过程中,我们都要手动进行事务的提交
,原因是 setAutoCommit()方法,在执行时它的值被设置为 false 了,所以我们在 CUD 操作中,必须通过
sqlSession.commit()`方法来执行提交操作
2. Mybatis中自动提交事务
-
在
SqlSession
中,openSession
方法是重载的,之前我们使用factory.openSession()
时,该方法会自动将autoCommit
设置为false
,即不会自动提交事务,我们必须自己手动提交事务
-
factory.openSession(boolean autoCommit)
:也可以使用该方法,将autoCommit设置为true
,这样就会自动提交事务
修改代码如下
执行结果:
我们发现,此时事务就设置为自动提交了,同样可以实现CUD操作时记录的保存。虽然这也是一种方式,但就编程而言,设置为自动提交方式为 false 再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交
14. Mybatis延迟加载策略
1. 什么是延迟加载
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载
懒加载的优点:
先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快
懒加载的缺点:
因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降