一般来说,我们直接从 https://github.com/mybatis/my... Fork到自己的仓库中,为什么要Fork呢?我们在之后的源码分析中,我们可能会加一些注释,英文翻译一波,方便自己理解,也方便自己自由提交。
啥也不多说,咱们直接看单元测试结构,除了 autoconstructor
这个包下是整体调试以外,其他的都是各个模块的单元测试。那咱们直接就从 org.apache.ibatis.autoconstructor
这个包下开始调试。
从这个包下主要包含下面几部分,如图所示:
见 mybatis-config.xml
作为MyBatis的配置文件,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> <!-- 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。 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
表。
包含AutoConstructorMapper.java AutoConstructorMapper.xml两个文件
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(); }
<?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
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
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; } }
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对象的时候会报错。
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
表 对应AutoConstructorTest.java文件,单元测试类。
@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"); }
右键任意一个测试方法debug搞起来。 IDEA调试技巧
本文由博客一文多发平台 OpenWrite 发布!