在进行源码分析前,先写一个使用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. 基于diango简易BLOG图片预览

    注册界面 登陆界面 博客主界面 个人站点主页 文章详情页 个人博客后台 添加文章页 修改密码页

  2. TFT2.2

    https://cdn-learn.adafruit.com/downloads/pdf/2-2-tft-display.pdf

  3. robotframework的字符类型转换,用Evaluate来转换

    ${b} BuiltIn.Set Variable 1.1 ${c}= BuiltIn.Evaluate float(${b}) ${d}= BuiltIn.Evaluate ${c}+2.2 1.有 ...

  4. jvm 年轻代、年老代、永久代

    关键字约定 Young generation –>新生代    Tenured / Old Generation –>老年代    Perm Area –>永久代 年轻代: 所有新生 ...

  5. IDEA+提示“Cannot resolve symbol XXXX”

    问题描述:鼠标放置下图中红色包上提示“Cannot resolve symbol XXXX”信息 解决: File->Invalidate Caches/Restart 清除缓存并重启 idea

  6. springboot使用lettuce连接池

    springboot对连接池的使用非常智能,配置文件中添加lettuce.pool相关配置,则会使用到lettuce连接池,并将相关配置设置为连接池相关参数,(前提是这些参数是springboot配置 ...

  7. WPF Binding学习(三)

    转自;http://blog.csdn.net/lisenyang/article/details/18312199 1.控件与控件间的双向绑定 WPF还支持控件作为数据源, <TextBox ...

  8. Android/Linux boot time分析优化

    如果需要优化boot time,就需要一个量化的工具来分析每个阶段的时间消耗.这种类型的优化特别适合使用基于timeline的图表,有着明显的时间顺序.要求不但能给出整个流程消耗的时间,还要能对流程进 ...

  9. 用Python实现大文件分割

    python代码如下: import sys,os kilobytes = 1024 megabytes = kilobytes*1000 chunksize = int(200*megabytes) ...

  10. Vue-组件使用细节

    一.用is指定组件为特定的原生HTML元素. html: <div id="app"> <table> <tbody> <item> ...