Skip to content

Commit e446742

Browse files
authored
Create Mybatis.md
1 parent 2a23f18 commit e446742

File tree

1 file changed

+223
-0
lines changed

1 file changed

+223
-0
lines changed

docs/Mybatis.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
2+
3+
4+
5+
# MyBatis 整体架构
6+
7+
MyBatis 最上面是接口层,接口层就是开发人员在 Mapper 或者是 Dao 接口中的接口定义,是查询、新增、更新还是删除操作;中间层是数据处理层,主要是配置 Mapper -> XML 层级之间的参数映射,SQL 解析,SQL 执行,结果映射的过程。上述两种流程都由基础支持层来提供功能支撑,基础支持层包括连接管理,事务管理,配置加载,缓存处理等。
8+
9+
![image-20200220202650971](C:\Users\吕明辉\AppData\Roaming\Typora\typora-user-images\image-20200220202650971.png)
10+
11+
## 接口层
12+
13+
在不与 Spring 集成的情况下,使用 MyBatis 执行数据库的操作主要如下:
14+
15+
```java
16+
InputStream is = Resources.getResourceAsStream("myBatis-config.xml");
17+
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
18+
SqlSessionFactory factory = builder.build(is);
19+
sqlSession = factory.openSession();
20+
```
21+
22+
其中的`SqlSessionFactory`,`SqlSession`是 MyBatis 接口的核心类,尤其是 SqlSession,这个接口是 MyBatis 中最重要的接口,这个接口能够让你执行命令,获取映射,管理事务。
23+
24+
#### **数据处理层**
25+
26+
- **配置解析**
27+
28+
在 Mybatis 初始化过程中,会加载 `mybatis-config.xml` 配置文件、映射配置文件以及 Mapper 接口中的注解信息,解析后的配置信息会形成相应的对象并保存到 `Configration` 对象中。之后,根据该对象创建 SqlSessionFactory 对象。待 Mybatis 初始化完成后,可以通过 SqlSessionFactory 创建 SqlSession 对象并开始数据库操作。
29+
30+
- **SQL 解析与 scripting 模块**
31+
32+
Mybatis 实现的动态 SQL 语句,几乎可以编写出所有满足需要的 SQL。
33+
34+
Mybatis 中 scripting 模块会根据用户传入的参数,解析映射文件中定义的动态 SQL 节点,形成数据库能执行的 SQL 语句。
35+
36+
- **SQL 执行**
37+
38+
SQL 语句的执行涉及多个组件,包括 MyBatis 的四大核心,它们是: `Executor``StatementHandler``ParameterHandler``ResultSetHandler`。SQL 的执行过程可以用下面这幅图来表示
39+
40+
![image-20200220202531623](C:\Users\吕明辉\AppData\Roaming\Typora\typora-user-images\image-20200220202531623.png)
41+
42+
43+
44+
#### **基础支持层**
45+
46+
- 反射模块
47+
48+
Mybatis 中的反射模块,对 Java 反射进行了很好的封装,提供了简易的 API,方便上层调用,并且对反射操作进行了一系列的优化,比如,缓存了类的 `元数据(MetaClass)`和对象的`元数据(MetaObject)`,提高了反射操作的性能。
49+
50+
- 类型转换模块
51+
52+
Mybatis 的别名机制,能够简化配置文件,该机制是类型转换模块的主要功能之一。类型转换模块的另一个功能**是实现 JDBC 类型与 Java 类型的转换**。在 SQL 语句绑定参数时,会将数据由 Java 类型转换成 JDBC 类型;在映射结果集时,会将数据由 JDBC 类型转换成 Java 类型。
53+
54+
- 日志模块
55+
56+
在 Java 中,有很多优秀的日志框架,如 Log4j、Log4j2、slf4j 等。Mybatis 除了提供了详细的日志输出信息,还能够集成多种日志框架,其日志模块的主要功能就是集成第三方日志框架。
57+
58+
- 资源加载模块
59+
60+
该模块主要封装了类加载器,确定了类加载器的使用顺序,并提供了加载类文件和其它资源文件的功能。
61+
62+
- 解析器模块
63+
64+
该模块有两个主要功能:一个是封装了 `XPath`,为 Mybatis 初始化时解析 `mybatis-config.xml`配置文件以及映射配置文件提供支持;另一个为处理动态 SQL 语句中的占位符提供支持。
65+
66+
- 数据源模块
67+
68+
Mybatis 自身提供了相应的数据源实现,也提供了与第三方数据源集成的接口。数据源是开发中的常用组件之一,很多开源的数据源都提供了丰富的功能,如连接池、检测连接状态等,选择性能优秀的数据源组件,对于提供 ORM 框架以及整个应用的性能都是非常重要的。
69+
70+
- 事务管理模块
71+
72+
一般地,Mybatis 与 Spring 框架集成,由 Spring 框架管理事务。但 Mybatis 自身对数据库事务进行了抽象,提供了相应的事务接口和简单实现。
73+
74+
- 缓存模块
75+
76+
Mybatis 中有`一级缓存``二级缓存`,这两级缓存都依赖于缓存模块中的实现。但是需要注意,这两级缓存与 Mybatis 以及整个应用是运行在同一个 JVM 中的,共享同一块内存,如果这两级缓存中的数据量较大,则可能影响系统中其它功能,所以需要缓存大量数据时,优先考虑使用 Redis、Memcache 等缓存产品。
77+
78+
- Binding 模块
79+
80+
在调用 `SqlSession` 相应方法执行数据库操作时,需要制定映射文件中定义的 SQL 节点,如果 SQL 中出现了拼写错误,那就只能在运行时才能发现。为了能尽早发现这种错误,Mybatis 通过 Binding 模块将用户自定义的 Mapper 接口与映射文件关联起来,系统可以通过调用自定义 Mapper 接口中的方法执行相应的 SQL 语句完成数据库操作,从而避免上述问题。注意,在开发中,我们只是创建了 Mapper 接口,而并没有编写实现类,这是因为 Mybatis 自动为 Mapper 接口创建了动态代理对象。
81+
82+
# MyBatis 核心组件
83+
84+
## SqlSessionFactory
85+
86+
SqlSessionFactory 是 MyBatis 框架中的一个接口,它主要负责的是
87+
88+
- MyBatis 框架初始化操作
89+
- 为开发人员提供`SqlSession` 对象
90+
91+
### SqlSessionFactory 的执行流程
92+
93+
下面来对 SqlSessionFactory 的执行流程来做一个分析
94+
95+
首先第一步是 SqlSessionFactory 的创建
96+
97+
```
98+
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
99+
```
100+
101+
从这行代码入手,首先创建了一个 `SqlSessionFactoryBuilder` 工厂,这是一个建造者模式的设计思想,由 builder 建造者来创建 SqlSessionFactory 工厂
102+
103+
然后调用 SqlSessionFactoryBuilder 中的 `build` 方法传递一个`InputStream` 输入流,Inputstream 输入流中就是你传过来的配置文件 mybatis-config.xml,SqlSessionFactoryBuilder 根据传入的 InputStream 输入流和`environment``properties`属性创建一个`XMLConfigBuilder`对象。SqlSessionFactoryBuilder 对象调用 XMLConfigBuilder 的`parse()`方法。
104+
105+
XMLConfigBuilder 会解析`/configuration`标签,configuration 是 MyBatis 中最重要的一个标签。
106+
107+
#### configuration 的配置
108+
109+
- `properties`,外部属性,这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。
110+
111+
```xml
112+
<properties>
113+
<property name="driver" value="com.mysql.jdbc.Driver" />
114+
<property name="url" value="jdbc:mysql://localhost:3306/test" />
115+
<property name="username" value="root" />
116+
<property name="password" value="root" />
117+
</properties>
118+
```
119+
120+
一般用来给 `environment` 标签中的 `dataSource` 赋值
121+
122+
```xml
123+
<environment id="development">
124+
<transactionManager type="JDBC" />
125+
<dataSource type="POOLED">
126+
<property name="driver" value="${driver}" />
127+
<property name="url" value="${url}" />
128+
<property name="username" value="${username}" />
129+
<property name="password" value="${password}" />
130+
</dataSource>
131+
</environment>
132+
```
133+
134+
* `settings` ,MyBatis 中极其重要的配置,它们会改变 MyBatis 的运行时行为。
135+
136+
可以在此标签内设置 缓存,懒加载,自动驼峰命名规则映射等。
137+
138+
```xml
139+
<settings>
140+
<setting name="cacheEnabled" value="true"/>
141+
<setting name="lazyLoadingEnabled" value="true"/>
142+
</settings>
143+
```
144+
145+
## SqlSession
146+
147+
在 MyBatis 初始化流程结束,也就是 SqlSessionFactoryBuilder -> SqlSessionFactory 的获取流程后,我们就可以通过 SqlSessionFactory 对象得到 `SqlSession` 然后执行 SQL 语句了。
148+
149+
SqlSession 对象是 MyBatis 中最重要的一个对象,这个接口能够让你执行命令,获取映射,管理事务。SqlSession 中定义了一系列模版方法,让你能够执行简单的 `CRUD` 操作,也可以通过 `getMapper` 获取 Mapper 层,执行自定义 SQL 语句,因为 SqlSession 在执行 SQL 语句之前是需要先开启一个会话,涉及到事务操作,所以还会有 `commit``rollback``close` 等方法。这也是模版设计模式的一种应用。
150+
151+
## Executor
152+
153+
#### **Executor 的继承结构**
154+
155+
每一个 SqlSession 都会拥有一个 Executor 对象,这个对象负责增删改查的具体操作,我们可以简单的将它理解为 JDBC 中 Statement 的封装版。也可以理解为 SQL 的执行引擎,要干活总得有一个发起人吧,可以把 Executor 理解为发起人的角色。
156+
157+
Executor 执行器,它有两个实现类,分别是`BaseExecutor``CachingExecutor`
158+
159+
`BaseExecutor` 是一个抽象类,这种通过抽象的实现接口的方式是`适配器设计模式之接口适配` 的体现,是 Executor 的默认实现,实现了大部分 Executor 接口定义的功能,降低了接口实现的难度。BaseExecutor 的子类有三个,分别是 SimpleExecutor、ReuseExecutor 和 BatchExecutor。
160+
161+
`SimpleExecutor` : 简单执行器,是 MyBatis 中**默认使用**的执行器,每执行一次 update 或 select,就开启一个 Statement 对象,用完就直接关闭 Statement 对象 (可以是 Statement 或者是 PreparedStatment 对象)
162+
163+
`ReuseExecutor` : 可重用执行器,这里的重用指的是重复使用 Statement,它会在内部使用一个 Map 把创建的 Statement 都缓存起来,每次执行 SQL 命令的时候,都会去判断是否存在基于该 SQL 的 Statement 对象,如果存在 Statement 对象并且对应的 connection 还没有关闭的情况下就继续使用之前的 Statement 对象,并将其缓存起来。因为每一个 SqlSession 都有一个新的 Executor 对象,所以我们缓存在 ReuseExecutor 上的 Statement 作用域是同一个 SqlSession。
164+
165+
`BatchExecutor` : 批处理执行器,用于将多个 SQL 一次性输出到数据库
166+
167+
`CachingExecutor`: 缓存执行器,先从缓存中查询结果,如果存在就返回之前的结果;如果不存在,再委托给 Executor delegate 去数据库中取,delegate 可以是上面任何一个执行器。
168+
169+
### Executor 的具体执行过程
170+
171+
* 当有一个查询请求访问的时候,首先会经过 Executor 的实现类 `CachingExecutor` ,先从缓存中查询 SQL 是否是第一次执行,如果是第一次执行的话,那么就直接执行 SQL 语句,并创建缓存,如果第二次访问相同的 SQL 语句的话,那么就会直接从缓存中提取。
172+
* 如果没有的话,就再重新创建 `Executor` 执行器执行 SQL 语句, 创建我们上面提到的三种执行器
173+
* 到这里,执行器所做的工作就完事了,Executor 会把后续的工作交给 `StatementHandler` 继续执行。
174+
175+
### StatementHandler
176+
177+
`StatementHandler` 是四大组件中最重要的一个对象,负责操作 Statement 对象与数据库进行交互,在工作时还会使用 `ParameterHandler``ResultSetHandler`对参数进行映射,对结果进行实体类的绑定
178+
179+
**StatementHandler 的继承结构**`Executor` 比较相似
180+
181+
主要有三个实现类
182+
183+
- **SimpleStatementHandler**: 管理 Statement 对象并向数据库中推送不需要预编译的 SQL 语句。
184+
- **PreparedStatementHandler**: 管理 Statement 对象并向数据中推送需要预编译的 SQL 语句。
185+
- **CallableStatementHandler**:管理 Statement 对象并调用数据库中的存储过程。
186+
187+
#### StatementHandler 的创建
188+
189+
MyBatis 会根据 SQL 语句的类型进行对应 StatementHandler 的创建 。
190+
191+
192+
193+
194+
195+
196+
197+
198+
199+
#### #{}和${}的区别是什么?
200+
201+
#{}是预编译处理,${}是字符串替换。mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;mybatis在处理${}时,就是把${}替换成变量的值。使用#{}可以有效的防止SQL注入,提高系统安全性。
202+
203+
#### Xml 映射文件中,除了常见的 select|insert|updae|delete 标签之外,还有哪些标签?
204+
205+
还有很多其他的标签, resultMap , parameterMap 加上动态 sql 的 9 个标签,`trim|where|set|foreach|if|choose|when|otherwise|bind`等,其中为 sql 片段标签,通过``标签引入 sql 片段,``为不支持自增的主键生成策略标签。
206+
207+
208+
209+
### mybatis 有几种分页方式?
210+
211+
数组分页
212+
213+
sql分页
214+
215+
拦截器分页
216+
217+
RowBounds分页
218+
219+
### mybatis 逻辑分页和物理分页的区别是什么?
220+
221+
- 物理分页速度上并不一定快于逻辑分页,逻辑分页速度上也并不一定快于物理分页。
222+
- 物理分页总是优于逻辑分页:没有必要将属于数据库端的压力加诸到应用端来,就算速度上存在优势,然而其它性能上的优点足以弥补这个缺点。
223+

0 commit comments

Comments
 (0)