在进行源码分析前,先写一个使用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. 牛客 小a与星际探索 bfs

    链接:https://ac.nowcoder.com/acm/contest/317/C?&headNav=acm来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ ...

  2. Java和Php比较

    这样从几个方面来看:一.运行机制:Java代码被编译成字节码后,会在虚拟机里由JIT进行二次编译成为本地码,据传言其执行速度可以和C++相媲美,经过我自己测试,用Java实现一个简单的Memcache ...

  3. visual studio发布到远程服务器的IIS

    visual studio发布到远程服务器的IIS 1.打开项目,选中发布的项目. 2.右键发布的项目,点击菜单中的“发布”,弹出发布配置窗体,如下图 3.选择“自定义”,如下图 4.填写发布配置的名 ...

  4. php 验证身份证号

    function validation_filter_id_card($id_card){ if(strlen($id_card)==18){ return idcard_checksum18($id ...

  5. autoware

    在 Autoware目录下执行 git checkout 将版本切换到1.10.0 因为最新版驱动有问题然后执行 sudo apt-get update sudo apt-get install -y ...

  6. D. Artsem and Saunders

    一个变换题 给定f(x),[1,n]->[1,n] 构造g(x),h(x)满足: g(h(x))=x [1,n]->[1,m] h(g(x))=f(x) [1,m]->[1,n] 根 ...

  7. C++模板参数类型(转载)

    实际上有三种类型模板参数:类型模板参数.无类型模板参数和模板模板参数(以模板作为模板的参数). .类型模板参数 类型模板参数是我们使用模板的主要目的.我们可以定义多个类型模板参数: template& ...

  8. 使用 OpenSSL 创建私有 CA:2 中间证书

    OpenSSL 创建私有 CA 三部曲:使用 OpenSSL 创建私有 CA:1 根证书使用 OpenSSL 创建私有 CA:2 中间证书使用 OpenSSL 创建私有 CA:3 用户证书 本文将在前 ...

  9. App Inspector-iOS真机功能详解

    前言: App Inspector:浏览器端的移动设备 UI 查看器,使用树状态结构查看 UI 布局,自动生成 XPaths.官网:https://macacajs.github.io/app-ins ...

  10. mariadb(第一章)

      数据库介绍 1.什么是数据库? 简单的说,数据库就是一个存放数据的仓库,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来组织,存储的,我们可以通过数据库提供的多种方法来 ...