【原创】Mybaitis生命周期源码解析-XML配置启动--转载请注明出处

一、准备基本代码

注:本文的一切内容都是基于XML配置启动进行的分析,不适用与Spring-mybatis组合使用场景。

1.创建基本类

package com.zhou;

import com.zhou.mapper.BlogMapper;
import com.zhou.pojo.Blog;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

public class Demo1SessionFactory {
    public static void main(String[] args) throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //从 XML 中构建 SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            BlogMapper mapper = session.getMapper(BlogMapper.class);
            Blog blog = mapper.selectBlog(1, new ArrayList<>());
            System.out.println(blog.getId());
            blog = mapper.selectBlog(10, new ArrayList<>());
            System.out.println(blog.getId());
        } finally {
            session.close();
        }
    }
}

2.创建基本的xml配置文件

<?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>
  <!-- 引入外部资源文件 -->
  <!-- 设置驼峰匹配 -->
  <settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
  </settings>
  <!-- 设置包扫描(别名)
  <typeAliases>
    <package name="com.zhou.pojo"/>
  </typeAliases>-->
  <!-- 配置环境:可以配置多个环境,default:配置某一个环境的唯一标识,表示默认使用哪个环境 -->
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <!-- 配置连接信息 -->
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://你的数据库地址:3306/库名"/>
        <property name="username" value="你的用户名"/>
        <property name="password" value="你的密码"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 配置映射文件:用来配置sql语句和结果集类型等 -->
  <mappers>
    <mapper resource="BlogMapper.xml"/>
  </mappers>
</configuration>

3.创建查询sql的mapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhou.mapper.BlogMapper">
  <select id="selectBlog" parameterType="java.lang.Integer" resultType="com.zhou.pojo.Blog">
    SELECT
    <if test="id != null">
        <foreach collection="ids" item="item">
            1 AS str,
        </foreach>
      #{id} AS id
    </if>
  </select>
</mapper>

4.根据上方的mapper.xml创建对应的POJO类以及mapper接口。

package com.zhou.pojo;

public class Blog {

    private Integer id;

    private String str;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}
package com.zhou.mapper;

import java.util.List;
import com.zhou.pojo.Blog;
import org.apache.ibatis.annotations.Param;

public interface BlogMapper {

    Blog selectBlog(@Param("id") Integer id, @Param("ids") List<Integer> ids);
}

二、SqlSessionFactory的构建

在进行构建sqlSessionFactory时,进行了以下的两步主要操作

1.读取config配置的信息到缓存中,并将其设置到Configuration类。在这个示例中,我们采用的是xml配置的方式因此,在加载配置时会使用xml的解析器解析配置文件中的信息,使用校验文件来进行校验输入配置参数的有效性,然后创建一个xml的dom对象。

 

2.将mapper的sql描述信息添加到Configuration类中。然后使用读取出来的xml信息缓存,调用XMLConfigBuilder格式化工具,来创建基本的mybatis的Configuration类信息。在完成了基本配置后,将mapper.xml中的信息读取出来,然后进行结构化处理,再保存到Configuration的mappedStatements中。

在mappedStatements中的数据结构,以下方的数据结构进行存储:

由上方的debug信息可以看出,这里将每一个sql,拆分成了多个不同的节点,并且每一个标签均为不同的节点类型,节点原本的属性信息,都已经被转换为了对象的属性。利用这些属性,就可以迅速的将sql加载出来。

三、Mapper实例的构建与调用

1.创建SqlSession。在调用SqlSessionFactory进行开启SqlSession时,首先创建了一个SqlSession对象,然后像这个对象中添加了executor的信息。但是要注意的是,在一开始开启SqlSession的时候,并没有进行数据库连接。

下方的debug信息,是执行查询前的SqlSession中的属性信息,可以看到在executor对象下的transaction对象中,虽然具有dataSource对象但是并没有connection对象,即数据库连接。

在执行过一次查询以后,便拥有了一个数据库连接在executor对象中,而之后,在这个session提交前,都会使用这个connection来进行sql的执行了。

2.利用SqlSession开启一个MapperProxy类对象。

首先从SqlSession对象中,获取到Configuration的对象,然后从该对象的MapperRegistry中获取相应的类的描述信息,再使用MapperProxyFactory构造出响应的MapperProxy对象,再从该对象中获取mapper接口的实现类返回给调用端。

DefaultSqlSession类中的getMapper方法,这里在getMapper的时候,将SqlSession自身作为参数传入了,所以在每个MapperProxy对象中都是具有一个SqlSession对象信息的。

MapperRegistry类中的getMapper方法:

MapperProxyFactory类中,进行构造MapperProxy对象的方法:

3.执行查询时,是利用java的反射来对类进行的实现,利用反射来实现类以后,再使用这个对象来调用sqlSession来执行查询操作。

首先调用MapperProxy类的invoke方法,该方法中,首先利用method来构建出所需要使用的MapperMethod类对象,这个类中,只会包含基本的method描述,如入参出参等。

在构造完成MapperMethod信息后,MapperMethod会使用MapperProxy类中持有的sqlSession对象,来执行sql。在这里查询的结果只有一个对象,因此使用的是下图中的方式来执行sql。

最后再进行实际的sql执行,返回查询到的数据。

四、总结

1.初始化

mybatis在进行初始化时,首先会由SqlSessionFactoryBuilder来创建SqlSessionFactory,在创建成功后,SqlSessionFactoryBuilder对象就会结束生命周期。SqlSessionFactory中,持有mybatis的Config信息,而Config信息中,除mybatis本身的信息外,还持有数据库连接池,以及mapper.xml中的信息,这些信息都在mybatis进行初始化时进行结构化缓存到了Configuration类中。其中,mapper.xml中的信息,被进行了良好的节点分割,每一个标签都被分割成独立的节点,来供mybatis进行快速组装sql信息。

2.执行sql

在进行sql的执行时,首先需要的是开启SqlSession,SqlSession由SqlSessionFactory进行创建。开启SqlSession后,由SqlSession来进行mapper的信息初始化,使用的则是MapperRegistry类,这个类在每次完成mapper的初始化后,就会结束生命周期,在反复创建mapper时,会需要多次的创建MapperRegistry对象。创建出的类对象以MapperProxy进行承载,在MapperProxy对象进行执行Sql时,则是将sql交予自身所持有的final的SqlSession来进行处理。在SqlSession中,采用的是懒汉单例模式来处理JdbcConnection,以此来达到事物处理的效果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章