1. 程式人生 > >【原創】Mybaitis生命週期原始碼解析-XML配置啟動--轉載請註明出處

【原創】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://192.168.1.251:3306/welian"/>
        <property name="username" value="welian"/>
        <property name="password" value="welian"/>
      </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物件。mapper物件構建完成後,在mapper中,不會直接具有JdbcConnection物件,而是引用了SqlSession物件。在SqlSession中,採用的是懶漢的單例模式來處理JdbcConnection,以此來達到事物處理的效果。