MyBatis 基礎搭建及架構概述

c旋兒發表於2019-07-11

MyBatis 是什麼?

MyBatis是第一個支援自定義SQL、儲存過程和高階對映的類持久框架。MyBatis消除了大部分JDBC的樣板程式碼、手動設定引數以及檢索結果。MyBatis能夠支援簡單的XML和註解配置規則。使Map介面和POJO類對映到資料庫欄位和記錄。

下面我們通過一個簡單的專案搭建來帶你認識一下MyBatis的使用和一些核心元件的講解。

MyBatis 專案構建

為了快速構建一個MyBatis專案,我們採用SpringBoot快速搭建的方式。搭建好後在對應的pom.xml下新增如下的maven依賴,主要作用在於引入mybatis一些jar包和類庫

主要分為四個步驟:

  1. 快速構建專案,引入核心maven dependency依賴
  2. 構建POJO類和介面式程式設計的 Mapper類,編寫SQL語句
  3. 編寫config.properties資料庫驅動等配置
  4. 構建Mybatis核心配置檔案即mybatis-config.xml,引入資料庫驅動,對映Mapper類
  5. 編寫Junit單元測試類
<!-- mybatis 核心依賴-->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.4.6</version>
</dependency>
<!-- 資料庫驅動包 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.25</version>
</dependency>
<!-- 單元測試包-->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
  <scope>test</scope>
</dependency>

為了便於更好的說明文章的主旨,這裡就不貼出全部程式碼了,會貼出核心程式碼部分

編寫對應的POJO類和介面式程式設計Mapper類,這裡我們以部門業務邏輯為例,構建一個部門類,有三個屬性即部門編號、部門名稱、位置,下面是部分程式碼:

Dept.java

package com.mybatis.beans;
public class Dept {
  
    private Integer deptNo;
    private String  dname;
    private String  loc;
  
    public Dept() {}
    public Dept(Integer deptNo, String dname, String loc) {
        this.deptNo = deptNo;
        this.dname = dname;
        this.loc = loc;
    }
        get and set...
}

MyBatis最核心的功能之一就是介面式程式設計,它可以讓我們編寫Mapper介面和XML檔案,從而把引數和返回結果對映到對應的欄位中。

DeptDao.java

package com.mybatis.dao;
public interface DeptDao {

    // 通過部門名稱查詢
    public Dept findByDname(String Dname);
    // 通過部門編號查詢
    public Dept findByDeptNo(Integer deptno);
}

在/resources 下新建com.mybatis.dao 包,在其內編寫對應的XML配置檔案,此XML配置檔案和Mapper互為對映關係。

<mapper namespace="com.mybatis.dao.DeptDao" >

    <sql id="DeptFindSql">
     select * from dept
    </sql>
  
    <select id="findByDeptNo" resultType="com.mybatis.beans.Dept">
        <include refid="DeptFindSql"></include>
        where deptno = #{deptNo}
    </select>

    <select id="findByDname" resultType="com.mybatis.beans.Dept">
        <include refid="DeptFindSql"></include>
        where dname = #{dname}
    </select>

</mapper>

上述的 就是對映到Mapper介面類的名稱空間

<select>標籤用於編寫查詢語句,查詢完成之後需要把結果對映到物件或者map集合等,需要用到resultType屬性指定對應的結果集。

上述採用了的標籤寫法,為了方便的對映到實體類,需要修改的話統一修改即可,降低耦合性。

構建完成基礎的SQL語句和對映之後,下面來構建MySQL資料庫驅動,在/resources 下建立config.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=123456

在/resources 下編寫MyBatis核心配置檔案myBatis-config.xml,引入資料庫驅動,對映Mapper類

<configuration>
    <!-- 設定匯入外部properties檔案位置 -->
    <properties resource="config.properties"></properties>
  
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <package name="com.mybatis.dao"/>
    </mappers>
</configuration>

configuration 標籤很像是Spring 中的 beans 標籤或者是基於註解的配置@Configuration,也就是MyBatis的核心配置環境,使用 properties 標籤引入外部屬性環境,也就是資料庫驅動配置,使用 mappers 對映到Mapper所在的包,這裡指的就是DeptDao.java所在的包。

在test包下面新建一個Junit單元測試類,主要流程如下:

MyBatis 基礎搭建及架構概述

MyBatisTest.java 程式碼如下:

public class MyBatisTest {

    private SqlSession sqlSession;


    /**
     * 讀取配置檔案,建立SQL工廠,開啟會話
     * @throws Exception
     */
    @Before
    public void start() throws Exception{
        InputStream is = Resources.getResourceAsStream("myBatis-config.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        sqlSession = factory.openSession();
    }

    /**
     * 銷燬會話
     */
    @After
    public void destroy() {
        if(sqlSession != null){
            sqlSession.close();
        }
    }

    @Test
    public void test(){
        DeptDao deptDao = sqlSession.getMapper(DeptDao.class);
        Dept dept = deptDao.findByDeptNo(1);
        System.out.println(dept.getDname());
    }
}

@Before 和 @After 是junit工具包中的類,@Before在執行@Test 測試其主要業務之前載入,@After 在執行@Test 測試完成之後載入。

整體結構如下:

MyBatis 基礎搭建及架構概述

MyBatis 整體架構

MyBatis的架構大概是這樣的,最上面是介面層,介面層就是開發人員在Mapper或者是Dao介面中的介面定義,是查詢、新增、更新還是刪除操作;中間層是資料處理層,主要是配置Mapper -> xml層級之間的引數對映,SQL解析,SQL執行,結果對映的過程。上述兩種流程都由基礎支援層來提供功能支撐,基礎支援層包括連線管理,事務管理,配置載入,快取處理。

MyBatis 基礎搭建及架構概述

介面層

在不與Spring 整合的情況下,使用MyBatis執行資料庫的操作主要如下:

InputStream is = Resources.getResourceAsStream("myBatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
sqlSession = factory.openSession();

其中的SqlSessionFactory,SqlSession是MyBatis介面的核心類,尤其是SqlSession,這個介面是MyBatis中最重要的介面,這個介面能夠讓你執行命令,獲取對映,管理事務。

資料處理層

  1. 配置解析

在Mybatis初始化過程中,會載入mybatis-config.xml配置檔案、對映配置檔案以及Mapper介面中的註解資訊,解析後的配置資訊會形成相應的物件並儲存到Configration物件中。之後,根據該物件建立SqlSessionFactory物件。待Mybatis初始化完成後,可以通過SqlSessionFactory建立SqlSession物件並開始資料庫操作。

  1. SQL解析與scripting模組

Mybatis實現的動態SQL語句,幾乎可以編寫出所有滿足需要的SQL。

Mybatis中scripting模組會根據使用者傳入的引數,解析對映檔案中定義的動態SQL節點,形成資料庫能執行的sql語句。

  1. SQL執行

SQL語句的執行涉及多個元件,包括MyBatis的四大神器,它們是: ExecutorStatementHandlerParameterHandlerResultSetHandler。SQL的執行過程可以

用下面這幅圖來表示

MyBatis 基礎搭建及架構概述

MyBatis層級結構各個元件的介紹(這裡只是簡單介紹,具體介紹在後面):

  • SqlSession: MyBatis核心API,主要用來執行命令,獲取對映,管理事務。接收開發人員提供Statement Id 和引數.並返回操作結果
  • Executor: 執行器,是MyBatis排程的核心,負責SQL語句的生成以及查詢快取的維護
  • StatementHandler: 封裝了JDBC Statement操作,負責對JDBC statement 的操作,如設定引數、將Statement結果集轉換成List集合。
  • ParameterHandler: 負責對使用者傳遞的引數轉換成JDBC Statement 所需要的引數
  • ResultSetHandler: 負責將JDBC返回的ResultSet結果集物件轉換成List型別的集合
  • TypeHandler: 用於Java型別和jdbc型別之間的轉換
  • MappedStatement: 動態SQL的封裝
  • SqlSource: 表示從XML檔案或註釋讀取的對映語句的內容,它建立將從使用者接收的輸入引數傳遞給資料庫的SQL。
  • Configuration: MyBatis所有的配置資訊都維持在Configuration物件之中

基礎支援層

該層保護mybatis的基礎模組,它們為核心處理層提供了良好的支撐。

(1)反射模組

Mybatis中的反射模組,對Java原生的反射進行了很好的封裝,提供了簡易的API,方便上層呼叫,並且對反射操作進行了一系列的優化,比如,快取了類的後設資料(MetaClass)和物件的後設資料(MetaObject),提高了反射操作的效能。

(2)型別轉換模組

Mybatis的別名機制,是為了簡化配置檔案的,該機制是型別轉換模組的主要功能之一。型別轉換模組的另一個功能是實現JDBC型別與Java型別間的轉換。該功能在SQL語句繫結實參和對映查詢結果集時都會涉及。在SQL語句繫結實參時,會將資料有Java型別轉換成JDBC型別;在對映結果集時,會將資料有JDBC型別轉換成Java型別。

(3)日誌模組

Java世界裡,有很多優秀的日誌框架,如Log4j、Log4j2、slf4j等。Mybatis除了提供了詳細的日誌輸出資訊,還能夠整合多種日誌框架,其日誌模組的主要功能就是整合第三方日誌框架。

(4)資源載入模組

該模組主要封裝了類載入器,確定了類載入器的使用順序,並提供了載入類檔案和其它資原始檔的功能。

(5) 解析器模組

該模組有兩個主要功能:一個是封裝了XPath,為Mybatis初始化時解析mybatis-config.xml配置檔案以及對映配置檔案提供支援;另一個為處理動態SQL語句中的佔位符提供支援。

(6)資料來源模組

在資料來源模組中,Mybatis自身提供了相應的資料來源實現,也提供了與第三方資料來源整合的介面。資料來源是開發中的常用元件之一,很多開源的資料來源都提供了豐富的功能,如,連線池、檢測連線狀態等,選擇效能優秀的資料來源元件,對於提供ORM框架以及整個應用的效能都是非常重要的。

(7)事務管理模組

一般地,Mybatis與Spring框架整合,由Spring框架管理事務。但Mybatis自身對資料庫事務進行了抽象,提供了相應的事務介面和簡單實現。

(8)快取模組

Mybatis中有一級快取和二級快取,這兩級快取都依賴於快取模組中的實現。但是,需要注意,這兩級快取與Mybatis以及整個應用是執行在同一個JVM中的,共享同一塊記憶體,如果這兩級快取中的資料量較大,則可能影響系統中其它功能,所以需要快取大量資料時,優先考慮使用Redis、Memcache等快取產品。

(9)Binding模組

在呼叫SqlSession相應方法執行資料庫操作時,需要制定對映檔案中定義的SQL節點,如果sql中出現了拼寫錯誤,那就只能在執行時才能發現。為了能儘早發現這種錯誤,Mybatis通過Binding模組將使用者自定義的Mapper介面與對映檔案關聯起來,系統可以通過呼叫自定義Mapper介面中的方法執行相應的SQL語句完成資料庫操作,從而避免上述問題。注意,在開發中,我們只是建立了Mapper介面,而並沒有編寫實現類,這是因為Mybatis自動為Mapper介面建立了動態代理物件。有時,自定義的Mapper介面可以完全代替對映配置檔案,但比如動態SQL語句啊等,還是寫在對映配置檔案中更好。

相關參考:

mybatis的整體架構 https://my.oschina.net/liuyuantao/blog/1860807

MyBatis框架的使用及原始碼分析(十) CacheExecutor,SimpleExecutor,BatchExecutor ,ReuseExecutor

《深入理解mybatis原理》 MyBatis的架構設計以及例項分析 https://blog.csdn.net/luanlouis/article/details/40422941

相關文章