MyBatis源码解析-搭建调试环境

MyBatis源码解析-搭建调试环境

1. 相关工具

  • Maven
  • Git
  • JDK1.8
  • IntelliJ IDEA

2. 源码拉取

通常来讲,咱们直接从https://github.com/mybatis/my... Fork到本身的仓库中,为何要Fork呢?咱们在以后的源码分析中,咱们可能会加一些注释,英文翻译一波,方便本身理解,也方便本身自由提交。java

  • 版本:3.5.4-SNAPSHOT

3. 调试

啥也很少说,我们直接看单元测试结构,除了autoconstructor这个包下是总体调试之外,其余的都是各个模块的单元测试。那我们直接就从org.apache.ibatis.autoconstructor这个包下开始调试。git

从这个包下主要包含下面几部分,如图所示:github

  • MyBatis的配置文件:mybatis-config.xml
  • SQL文件: CreateDB.sql
  • 映射及配置:AutoConstructorMapper.java AutoConstructorMapper.xml
  • 实体类:AnnotatedSubject.java BadSubject.java ExtensiveSubject.java PrimitiveSubject.java
  • 测试类:AutoConstructorTest.java

3.1 MyBatis的配置文件

mybatis-config.xml 做为MyBatis的配置文件,xml配置代码以下:sql

<?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表。apache

3.3 映射及配置

包含AutoConstructorMapper.java AutoConstructorMapper.xml两个文件mybatis

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里处理会有些麻烦。app

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调试技巧

本文由博客一文多发平台 OpenWrite 发布!
相关文章
相关标签/搜索