在进行源码分析前,先写一个使用mybatis进行开发的demo,方便我们后面进行分析。

一 关于mybatis的demo

 pom.xml文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.yht</groupId>
<artifactId>mybatisTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>mybatisTest</name>
<url>http://maven.apache.org</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency> <!-- 添加log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency> <!-- 添加mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.6</version>
</dependency> <!-- 添加mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.12</version>
</dependency> </dependencies> </project>

配置文件spring-ibatis:

<?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="db.properties"></properties> <environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" /> </dataSource>
</environment>
</environments> <!-- 映射文件 -->
<mappers>
<mapper resource="com/yht/mybatisTest/dao/goods.xml" />
</mappers> </configuration>

数据库连接信息 db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/silk
username=root
password=123456

创建一张Goods商品表

CREATE TABLE `goods` (
`id` varchar(50) NOT NULL COMMENT '商品ID',
`name` varchar(255) NOT NULL COMMENT '商品标题',
`detail` varchar(20) DEFAULT NULL,
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品信息';

创建Goods实体类

public class Goods {

    private String id;
private String name;
private String remark;
private String detail;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
} }

创建GoodsDao接口

public interface GoodsDao {

    public Goods selectGoodsById(String goodsId);

}

Mapper配置文件goods.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
<mapper namespace="com.yht.mybatisTest.dao.GoodsDao">
<select id="selectGoodsById" resultType="com.yht.mybatisTest.entity.Goods" >
select * from goods where id = #{id}
</select>
</mapper>

编写测试用例:

public class GoodsDaoTest {

    @Test
public void selectGoodsTest(){

// 共有四个步骤,接下来就针对这四个步骤进行分析

// 1.加载配置文件
          // 2.加载Mapper映射文件
          // 3.生成Mapper代理对象
          // 4.调用方法执行sql的过程

        SqlSession sqlSession = getSqlSessionFactory().openSession();
GoodsDao goodsMapper = sqlSession.getMapper(GoodsDao.class);
Goods goods = goodsMapper.selectGoodsById("1");
System.out.println("id="+goods.getId()+";name="+goods.getName());
} public static SqlSessionFactory getSqlSessionFactory() {
SqlSessionFactory sqlSessionFactory = null;
String resource = "spring-ibatis.xml"; try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources
.getResourceAsReader(resource));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sqlSessionFactory;
} }

目录结构如图:

以上就是所有的代码部分,接下来进行源码分析。

二 源码分析

由测试用例可知,在对数据库进行操作前,已经把相关的配置文件信息进行了加载解析,这个加载解析过程是怎样的呢?

从这行代码 new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource)); 入手,配置文件resource转化为Reader,然后传参到build方法中,那么就进入build这个方法:

public class SqlSessionFactoryBuilder {

//可以看到 build 方法可以接受多种参数组合
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
} public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
} public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
} public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// 将配置文件包装成了XMLConfigBuilder类,进入该构造器可知,其实是把配置文件封装到了XPathParse中
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 进入parser.parse方法
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}

进入XMLConfigBuilder类:

// 这是它的三个属性
private boolean parsed; //表示此XMLConfigBuilder是否经过解析
private XPathParser parser;//资源文件信息其实是封装到了这个类中
private String environment;

//这个就是解析配置文件的方法,重点就是在这里
// parser.evalNode("/configuration")的作用就是获取此配置文件的根节点configuration
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}

在这个用例中configuration根节点是什么样的呢?看下图:

然后进入parseConfiguration方法:这个方法就是对configuration根节点下所有的子节点进行解析,并把数据存放起来方便后面使用,子节点共有十种类型。

  private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}

现在相当于进入了大门,里面有十个小门等着我们进去一个个去探究,接下来的文章将对这十种子节点的解析过程进行讲解。

mybatis源码分析(一)------------入门的更多相关文章

  1. MyBatis 源码分析系列文章合集

    1.简介 我从七月份开始阅读MyBatis源码,并在随后的40天内陆续更新了7篇文章.起初,我只是打算通过博客的形式进行分享.但在写作的过程中,发现要分析的代码太多,以至于文章篇幅特别大.在这7篇文章 ...

  2. MyBatis 源码分析系列文章导读

    1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...

  3. MyBatis源码分析-MyBatis初始化流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  4. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  5. MyBatis源码分析(5)——内置DataSource实现

    @(MyBatis)[DataSource] MyBatis源码分析(5)--内置DataSource实现 MyBatis内置了两个DataSource的实现:UnpooledDataSource,该 ...

  6. MyBatis源码分析(4)—— Cache构建以及应用

    @(MyBatis)[Cache] MyBatis源码分析--Cache构建以及应用 SqlSession使用缓存流程 如果开启了二级缓存,而Executor会使用CachingExecutor来装饰 ...

  7. MyBatis源码分析(3)—— Cache接口以及实现

    @(MyBatis)[Cache] MyBatis源码分析--Cache接口以及实现 Cache接口 MyBatis中的Cache以SPI实现,给需要集成其它Cache或者自定义Cache提供了接口. ...

  8. MyBatis源码分析(2)—— Plugin原理

    @(MyBatis)[Plugin] MyBatis源码分析--Plugin原理 Plugin原理 Plugin的实现采用了Java的动态代理,应用了责任链设计模式 InterceptorChain ...

  9. 【MyBatis源码分析】select源码分析及小结

    示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...

  10. MyBatis源码分析之环境准备篇

    前言 之前一段时间写了[Spring源码分析]系列的文章,感觉对Spring的原理及使用各方面都掌握了不少,趁热打铁,开始下一个系列的文章[MyBatis源码分析],在[MyBatis源码分析]文章的 ...

随机推荐

  1. css滚动条样式自定义

    很简单的几行代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  2. ant.design React使用Echarts,实力踩坑

    最近项目用到Echarts(以下用ec代替),于是照猫画虎得引入到团队的antd项目中,但是遇到2个棘手问题: 1. ec对dom不渲染,检查后发现,原来是全局存在id重复,所以使用React时,最好 ...

  3. WPF DataGrid 列宽填充表格方法

    WPF中使DataGrid 列宽填充表格方法,设置ColumnWidth属性为ColumnWidth="*"即可. 源码: <DataGrid AutoGenerateCol ...

  4. ubantu搭建oj——第一天(6.11)

    oj第一份作业: 按照DMOJ的文档将代码搬运到ubantu上 sudo apt install git gcc g++ make python-dev libxml2-dev libxslt1-de ...

  5. ActiveMQ发布订阅模式 转发 https://www.cnblogs.com/madyina/p/4127144.html

    ActiveMQ的另一种模式就SUB/HUB即发布订阅模式,是SUB/hub就是一拖N的USB分线器的意思.意思就是一个来源分到N个出口.还是上节的例子,当一个订单产生后,后台N个系统需要联动,但有一 ...

  6. java kafka单列模式生产者客户端

    1.所需要的依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="ht ...

  7. Java多线程(三)—— synchronized关键字详解

    一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...

  8. Recurrent Neural Network[SRU]

    0.背景 对于如机器翻译.语言模型.观点挖掘.问答系统等都依赖于RNN模型,而序列的前后依赖导致RNN并行化较为困难,所以其计算速度远没有CNN那么快.即使不管训练的耗时程度,部署时候只要模型稍微大点 ...

  9. ASP MD5

    <% Private Const BITS_TO_A_BYTE = 8 Private Const BYTES_TO_A_WORD = 4 Private Const BITS_TO_A_WOR ...

  10. UVA10838 The Pawn Chess

    UVA好题没人写系列,感觉可以稍稍练习一下面向对象编程的形式(大雾) 题意很简单,在国际象棋的棋盘中有一些兵,走到对方底线即为胜利,问最优决策下谁能获胜.并输出最小步数. 首先这里的棋盘都只有\(4\ ...