【原創】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,以此來達到事物處理的效果。

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