前言
Mybatis做为一种半ORM框架(半:需要手动写sql)。ORM(Object Relational Mapping)的技术本质是:ORM框架将对象的值
映射到 对应数据库类型
: 如 String -> varchar。
且mybatis分为两种实现方式:基于xml和基于注解,本文为xml。
Mybatis源码(三)如何操作数据库
MyBatis源码(二)如何执行sql
Mybatis源码(一)获取数据源
如何看源码
看源码过程:
宏观 -> 微观 -> 图解(总结),我们要把握核心主干代码,不要过于纠结过细的实现,最终主干代码的拓展的细微代码都会汇聚于主干代码。
结构小结
分析main函数:
public class MybatisMain {
public static void main(String[] args) throws IOException {
String resource = "mapper/config/mybatis-config.xml"; //全局配置
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession();
OrderPojo orderPojo = session.selectOne("com.cbry.mybatis.OrderDao.findSimpleOrderInfo" , 0);
System.out.println(orderPojo);
}
}
我们将一条简单SQL的执行分为三个部分:
- Mybatis是如何获取数据库源
- Mybatis是如何获取SQL
- Mybatis是如何操作数据库
解析xml文件树状图:
获取数据库源
获取配置文件参数
首先通过Resources.getResourceAsStream , 获取mybaris-config.xml配置信息; 通过这些参数构建SqlSessionFactory:
官网具体配置信息介绍:https://mybatis.net.cn/configuration.html
mybatis-sourcecode.properties
其中在:<properties resource="mybatis-sourcecode.properties"></properties>
配置文本流的参数,使用如下:${cbry.datasource.password}:
#mybatis 源码的数据库信息配置
cbry.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
cbry.datasource.url=jdbc:mysql://localhost:3306/cbry?useUnicode=ture&characterEncoding=UTF-8&serverTimezone=GMT%2B8&characterEncoding=utf-8
cbry.datasource.username=root
cbry.datasource.password=123456
mybaris-config.xml
ps:二级缓存的配置生效与否在此设置。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="mybatis-sourcecode.properties"></properties>
<settings>
<!-- 打印查询语句 -->
<setting name="logImpl" value="STDOUT_LOGGING" />
<!-- 控制全局缓存(二级缓存)-->
<setting name="cacheEnabled" value="true"/>
<!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 -->
<!--
MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。
-->
<setting name="localCacheScope" value="SESSION"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/><!-- 单独使用时配置成MANAGED没有事务 -->
<dataSource type="POOLED">
<property name="driver" value="${cbry.datasource.driver-class-name}"/>
<property name="url" value="${cbry.datasource.url}"/>
<property name="username" value="${cbry.datasource.username}"/>
<property name="password" value="${cbry.datasource.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/orderDao.xml"/>
</mappers>
</configuration>
构建SqlSessionFactory
对应代码
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSessionFactory -> build -> XMLConfigBuilder -> parse方法
获取mybatis-config配置文件
parse方法:
evaNode传入string , 返回XNode对象:是mybatis-config.xml全局配置里面的内容(这个要实操获取值)
xml文件格式附讲
mybatis-config.xml文件配置里面的参数存在头部的dtd文件
具体值可以参考mybatis官网的mybatis-config.xml的参数
即标签的格式、属性类型等,左键点击即可进去。
截取对应信息(以数据库信息为例)
讲mybatis-config.xml全局配置文件的子内容截取,封装到对应对象,再将其注入SqlSessionFactory。将数据库源信息获取注入到环境: jdbc.prrperties等。继续下走:比如属性:environment对象
属性赋值set入参:XNode context , 依旧是config的完整文本。
到了 实际方法里面xxxElement截取对应部分的文本,比如environmentsElement里面就是datasource的子部分
将对应的赋予在对应的datasourceFactory里面
实例化对应子信息对象
每一个配置信息都对应了一个实例化类,那么如何对应不同类型的实例化类呢?比如说<dataSource type="POOLED">
可以看到resolveClass里面维护了一个hashMap,其value是类名。然后实例话这个对象,
就此我们找到了数据源。最终ds -> environment.set -> configuration.set。来存储
后续
此处已经获取datasource的信息,后面下文获取mapper的执行sql,是与此出处的environmentElement同级执行代码的mappersElement方法,如下。
小结
总体来说,还是先通过文本流获取文本配置,类似的有java获取普通参数文件和含有section的参数文件中的参数。然后通过解析xml树状结构,通过不同的子内容,实例化不同类型的实例化类对象封装对应的xml子内容,而后存放在SqlSessionFactory里面的configuration,比如说environment,mappers等。到时候创建sqlsession或者执行sql的时候取用。
但是从源码的浏览,我们发现了如mappers的四种构造的优先级的原因。
Mybatis是如何获取数据库源,类结构(截图于视频):