MyBatis源碼解析-搭建調試環境

MyBatis源碼解析-搭建調試環境

1. 相關工具

  • Maven
  • Git
  • JDK1.8
  • IntelliJ IDEA

2. 源碼拉取

通常來講,咱們直接從https://github.com/mybatis/mybatis-3 Fork到本身的倉庫中,爲何要Fork呢?咱們在以後的源碼分析中,咱們可能會加一些註釋,英文翻譯一波,方便本身理解,也方便本身自由提交。java

  • 版本:3.5.4-SNAPSHOT

3. 調試

啥也很少說,我們直接看單元測試結構,除了autoconstructor這個包下是總體調試之外,其餘的都是各個模塊的單元測試。那我們直接就從org.apache.ibatis.autoconstructor這個包下開始調試。git

從這個包下主要包含下面幾部分,如圖所示:github

  • MyBatis的配置文件:mybatis-config.xmlsql

  • SQL文件: CreateDB.sql數據庫

  • 映射及配置:AutoConstructorMapper.java AutoConstructorMapper.xmlapache

  • 實體類:AnnotatedSubject.java BadSubject.java ExtensiveSubject.java PrimitiveSubject.java微信

  • 測試類:AutoConstructorTest.javamybatis

3.1 MyBatis的配置文件

mybatis-config.xml 做爲MyBatis的配置文件,xml配置代碼以下:app

<?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>
    <!-- autoMappingBehavior should be set in each test case -->

    <!--  環境配置  -->
    <environments default="development">
        <environment id="development">
            <!-- 事務管理配置 -->
            <transactionManager type="JDBC">
                <property name="" value=""/>
            </transactionManager>
            <!-- 數據源配置 -->
            <dataSource type="UNPOOLED">
                <property name="driver" value="org.hsqldb.jdbcDriver"/>
                <property name="url" value="jdbc:hsqldb:mem:automapping"/>
                <property name="username" value="sa"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 掃描的Mapper文件 -->
    <mappers>
        <mapper resource="org/apache/ibatis/autoconstructor/AutoConstructorMapper.xml"/>
    </mappers>

</configuration>
  • 環境配置:在</environment>標籤中,配置了事務管理和數據源,數據庫選擇方面使用了HSQLDB,減小外部依賴。
  • 掃描映射:在<mappers>配置了要掃描的Mapper文件,這裏只配置了AutoConstructorMapper.xml。

3.2 SQL文件

CreateDB.sql 在單元測試中用做初始化數據庫的表及數據。以下:框架

DROP TABLE subject
IF EXISTS;

DROP TABLE extensive_subject
IF EXISTS;

CREATE TABLE subject (
  id     INT NOT NULL,
  name   VARCHAR(20),
  age    INT NOT NULL,
  height INT,
  weight INT,
  active BIT,
  dt     TIMESTAMP
);

CREATE TABLE extensive_subject (
  aByte      TINYINT,
  aShort     SMALLINT,
  aChar      CHAR,
  anInt      INT,
  aLong      BIGINT,
  aFloat     FLOAT,
  aDouble    DOUBLE,
  aBoolean   BIT,
  aString    VARCHAR(255),
  anEnum     VARCHAR(50),
  aClob      LONGVARCHAR,
  aBlob      LONGVARBINARY,
  aTimestamp TIMESTAMP
);

INSERT INTO subject VALUES
  (1, 'a', 10, 100, 45, 1, CURRENT_TIMESTAMP),
  (2, 'b', 10, NULL, 45, 1, CURRENT_TIMESTAMP),
  (2, 'c', 10, NULL, NULL, 0, CURRENT_TIMESTAMP);

INSERT INTO extensive_subject
VALUES
  (1, 1, 'a', 1, 1, 1, 1.0, 1, 'a', 'AVALUE', 'ACLOB', 'aaaaaabbbbbb', CURRENT_TIMESTAMP),
  (2, 2, 'b', 2, 2, 2, 2.0, 2, 'b', 'BVALUE', 'BCLOB', '010101010101', CURRENT_TIMESTAMP),
  (3, 3, 'c', 3, 3, 3, 3.0, 3, 'c', 'CVALUE', 'CCLOB', '777d010078da', CURRENT_TIMESTAMP);

包含兩張表:subject表和extensive_subject表。

3.3 映射及配置

包含AutoConstructorMapper.java AutoConstructorMapper.xml兩個文件

3.3.1 AutoConstructorMapper.java

package org.apache.ibatis.autoconstructor;

import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface AutoConstructorMapper {
  // PrimitiveSubject
  @Select("SELECT * FROM subject WHERE id = #{id}")
  PrimitiveSubject getSubject(final int id);

  // PrimitiveSubject
  @Select("SELECT * FROM subject")
  List<PrimitiveSubject> getSubjects();

  // AnnotatedSubject
  @Select("SELECT * FROM subject")
  List<AnnotatedSubject> getAnnotatedSubjects();
  
  // BadSubject
  @Select("SELECT * FROM subject")
  List<BadSubject> getBadSubjects();

  // ExtensiveSubject
  @Select("SELECT * FROM extensive_subject")
  List<ExtensiveSubject> getExtensiveSubjects();
}
  • 使用註解方式配置mapper,在開發中基於xml配置的仍是用的多一些,比較靈活。推薦xml配置。

3.3.2 AutoConstructorMapper.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="org.apache.ibatis.autoconstructor.AutoConstructorMapper">
</mapper>
  • 映射接口:org.apache.ibatis.autoconstructor.AutoConstructorMapper

3.4 實體類

3.4.1 AnnotatedSubject.java

​ AnnotatedSubject類中除了字段還有默認的構造函數之外,還提供一個以基本數據包裝類做爲構造參數的構造函數。注:@AutomapConstructor 這個註解的做用是讓框架自動使用這個構造器。【這裏重點說一下,咱們在使用MyBatis的時候,實體類的字段類型最好使用包裝類,最好不要設置默認值,不然xml裏處理會有些麻煩。

package org.apache.ibatis.autoconstructor;  

import org.apache.ibatis.annotations.AutomapConstructor;

public class AnnotatedSubject {
  private final int id;
  private final String name;
  private final int age;
  private final int height;
  private final int weight;


  public AnnotatedSubject(final int id, final String name, final int age, final int height,   final int weight) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.height = height;
    this.weight = weight;
  }

  //自動映射構造器 基本類型包裝類做爲構造參數
  @AutomapConstructor
  public AnnotatedSubject(final int id, final String name, final int age, final Integer height, final Integer weight) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.height = height == null ? 0 : height;
    this.weight = weight == null ? 0 : weight;
  }
}
  • 對應subject
  • 使用自動映射構造器註解@AutomapConstructor,開發過程當中我不多用到。
3.4.1.1 PrimitiveSubject.java
package org.apache.ibatis.autoconstructor;

import java.util.Date;

public class PrimitiveSubject {
  private final int id;
  private final String name;
  private final int age;
  private final int height;
  private final int weight;
  private final boolean active;
  private final Date dt;

  public PrimitiveSubject(final int id, final String name, final int age, final int height, final int weight, final boolean active, final Date dt) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.height = height;
    this.weight = weight;
    this.active = active;
    this.dt = dt;
  }
}
3.4.1.2 BadSubject.java
package org.apache.ibatis.autoconstructor;

public class BadSubject {
  private final int id;
  private final String name;
  private final int age;
  private final Height height;
  private final Double weight;

  public BadSubject(final int id, final String name, final int age, final Height height, final Double weight) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.height = height;
    this.weight = weight == null ? 0 : weight;
  }

  private class Height {

  }
}
  • 對應subject

  • 和上面AnnotatedSubject類的構造函數不一樣,在其構造參數中使用類型 Height,而不是Integer。由於MyBatis找不到Height映射的配置,因此在構造BadSubject對象的時候會報錯。

    3.4.2 ExtensiveSubject.java

    package org.apache.ibatis.autoconstructor;
    
    public class ExtensiveSubject {
        private final byte aByte;
        private final short aShort;
        private final char aChar;
        private final int anInt;
        private final long aLong;
        private final float aFloat;
        private final double aDouble;
        private final boolean aBoolean;
        private final String aString;
    
        // enum types
        private final TestEnum anEnum;
    
        // array types
    
        // string to lob types:
        private final String aClob;
        private final String aBlob;
    
        public ExtensiveSubject(final byte aByte,
                                final short aShort,
                                final char aChar,
                                final int anInt,
                                final long aLong,
                                final float aFloat,
                                final double aDouble,
                                final boolean aBoolean,
                                final String aString,
                                final TestEnum anEnum,
                                final String aClob,
                                final String aBlob) {
            this.aByte = aByte;
            this.aShort = aShort;
            this.aChar = aChar;
            this.anInt = anInt;
            this.aLong = aLong;
            this.aFloat = aFloat;
            this.aDouble = aDouble;
            this.aBoolean = aBoolean;
            this.aString = aString;
            this.anEnum = anEnum;
            this.aClob = aClob;
            this.aBlob = aBlob;
        }
    
        public enum TestEnum {
            AVALUE, BVALUE, CVALUE;
        }
    }
  • 對應extensive_subject
  • 相對於AnnotatedSubject這個稍微複雜一些,對象屬性幾乎包含了全部類型的數據。

3.5 測試類

對應AutoConstructorTest.java文件,單元測試類。

3.5.1 setUp

@BeforeAll
static void setUp() throws Exception {
  // create a SqlSessionFactory
  //讀取 mybatis-config.xml 配置建立 SqlSessionFactory 對象
  try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml")) {
    sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
  }

  // populate in-memory database
  // 讀取CreateDB.sql文件初始化數據到內存數據庫中
  BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
      "org/apache/ibatis/autoconstructor/CreateDB.sql");
}
  • @BeforeAll 這個註解是JUnit5提供的一個註解,做用:註釋的靜態方法會在執行全部測試用例以前調用,其餘詳細介紹能夠參考 JUnit4與JUnit5註解對比
  • 讀取 mybatis-config.xml 配置建立 SqlSessionFactory 對象
  • 讀取CreateDB.sql文件初始化數據到內存數據庫中

3.5.2 Run Test

右鍵任意一個測試方法debug搞起來。IDEA調試技巧

本文由 Janker 創做,採用 CC BY 3.0 CN協議 進行許可。 可自由轉載、引用,但需署名做者且註明文章出處。如轉載至微信公衆號,請在文末添加做者公衆號二維碼。

相關文章
相關標籤/搜索