乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 MyBatis概述与快速上手

    • 本章定位
    • MyBatis简介
    • 环境搭建
    • 第一个MyBatis程序
    • SqlSessionFactoryBuilder与openSession重载
    • SqlSessionFactory与SqlSession
    • SqlSession核心方法
    • 不使用 XML 构建 SqlSessionFactory
    • Mapper接口与映射方式
    • Java API 目录结构
  • 第2章 全局配置文件详解

    • 本章定位
    • properties
    • settings
    • typeAliases
    • typeHandlers
    • objectFactory
    • plugins
    • environments
    • transactionManager
    • dataSource
    • databaseIdProvider
    • mappers
    • 日志配置
  • 第3章 SQL映射文件基础

    • 本章定位
    • select
    • insert
    • update
    • delete
    • 参数传递与占位符
    • 主键生成策略
    • resultType
    • resultMap
    • 自动映射详解
    • sql片段
    • SQL 语句构建器
  • 第4章 动态SQL

    • 本章定位
    • if
    • choose、when、otherwise
    • where
    • set
    • foreach
    • trim
    • bind
    • script 元素:在注解映射器中启用动态 SQL
    • _databaseId 与动态 SQL 的多数据库支持
    • 动态 SQL 中插入脚本语言
  • 第5章 结果映射与关联查询

    • 本章定位
    • resultMap详解
    • association
    • collection
    • discriminator
    • N+1查询问题
    • 延迟加载
  • 第6章 MyBatis注解开发

    • 本章定位
    • @Select
    • @Insert
    • @Update
    • @Delete
    • @Param
    • @Options
    • @SelectKey
    • @Results
    • @Result
    • @One
    • @Many
    • @SelectProvider
  • 第7章 缓存与性能优化

    • 本章定位
    • 一级缓存
    • 二级缓存
    • 缓存配置详解
    • 自定义缓存
    • Executor执行器类型
    • 分页插件

typeAliases

导学

本节学习目标:

  • 理解 typeAliases 解决的核心痛点:全限定类名冗长、易错、可读性差
  • 掌握单个别名注册(typeAlias)与包扫描注册(package)两种方式
  • 熟记 MyBatis 内置常用别名,避免重复注册
  • 能够在项目中合理规划别名命名,提升 Mapper XML 的可维护性

定义

在 Mapper XML 中,每次引用 Java 类型都需要写全限定名:

<select id="findById" resultType="com.feixiang.entity.Employee">

当包层次深、类名长时,这种写法不仅繁琐,还容易因拼写错误导致启动失败。typeAliases 元素的作用就是为 Java 类设置一个简短、易记的别名,让 XML 配置更加简洁直观。


适用位置与核心属性

typeAliases 位于 mybatis-config.xml 中 settings 之后、typeHandlers 之前。

单个别名注册

<typeAliases>
  <typeAlias type="com.feixiang.entity.Employee" alias="Employee"/>
</typeAliases>
属性是否必填说明
type必填需要注册别名的全限定类名
alias可选指定的别名。若省略,MyBatis 会自动将类名的首字母小写作为别名(Employee → employee)

包扫描注册

<typeAliases>
  <package name="com.feixiang.entity"/>
</typeAliases>
属性是否必填说明
name必填需要扫描的包路径。该包下所有类(不含内部类、接口)都会被自动注册别名

包扫描时,若类上有 @Alias("Emp") 注解,则使用注解值作为别名;否则默认首字母小写的类名。


核心原理

别名解析与注册流程

核心存储结构:TypeAliasRegistry 内部维护一个 HashMap<String, Class<?>>,key 为别名,value 为对应的 Java 类。MyBatis 内置别名在 TypeAliasRegistry 构造时就被预先注册。


完整示例

场景说明

乐途公司员工管理系统包含多个实体类:Employee、Department、Position、SalaryRecord。为了避免在 Mapper XML 中反复书写冗长的全限定名,需要为实体包配置别名扫描,同时为一个常用的自定义类型单独注册别名。

操作前的状态

实体类目录:

com.feixiang.entity/
├── Employee.java
├── Department.java
├── Position.java
├── SalaryRecord.java

未配置别名前的 Mapper XML:

<select id="selectById" resultType="com.feixiang.entity.Employee">

完整配置代码

mybatis-config.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>

  <properties resource="db.properties"/>
  <settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
  </settings>

  <!-- 别名配置 -->
  <typeAliases>
    <!-- 方式一:单个别名注册(适合少量类或需要自定义别名时) -->
    <typeAlias type="com.feixiang.entity.Employee" alias="Emp"/>

    <!-- 方式二:包扫描注册(推荐,批量处理实体类) -->
    <package name="com.feixiang.entity"/>
  </typeAliases>

  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>

  <mappers>
    <mapper resource="mapper/EmployeeMapper.xml"/>
    <mapper resource="mapper/DepartmentMapper.xml"/>
  </mappers>

</configuration>

配置别名后的 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.feixiang.mapper.EmployeeMapper">

  <!-- 使用自定义别名 Emp -->
  <select id="selectById" resultType="Emp">
    SELECT employee_id, employee_name, department_code, create_time
    FROM employee
    WHERE employee_id = #{id}
  </select>

  <!-- 使用包扫描自动生成的别名 employee(Employee 首字母小写) -->
  <select id="selectAll" resultType="employee">
    SELECT * FROM employee
  </select>

</mapper>

DepartmentMapper.xml:

<mapper namespace="com.feixiang.mapper.DepartmentMapper">
  <!-- 使用包扫描别名 department -->
  <select id="selectByCode" resultType="department">
    SELECT department_code, department_name
    FROM department
    WHERE department_code = #{code}
  </select>
</mapper>

实际效果/结果

启动日志(开启 DEBUG 级别):

DEBUG org.apache.ibatis.io.ResolverUtil - Checking to see if class com.feixiang.entity.Employee matches criteria [is assignable to Object]
DEBUG org.apache.ibatis.type.TypeAliasRegistry - Registered type alias 'Emp' to 'com.feixiang.entity.Employee'
DEBUG org.apache.ibatis.type.TypeAliasRegistry - Registered type alias 'employee' to 'com.feixiang.entity.Employee'
DEBUG org.apache.ibatis.type.TypeAliasRegistry - Registered type alias 'department' to 'com.feixiang.entity.Department'
DEBUG org.apache.ibatis.type.TypeAliasRegistry - Registered type alias 'position' to 'com.feixiang.entity.Position'
DEBUG org.apache.ibatis.type.TypeAliasRegistry - Registered type alias 'salaryRecord' to 'com.feixiang.entity.SalaryRecord'

查询执行成功,结果正确映射到实体对象。

分析

  • Emp 是显式注册的自定义别名,优先级与自动生成的 employee 并存,两者指向同一类
  • 包扫描会递归扫描指定包下的所有类,但不会扫描子包(如需扫描子包需单独配置 <package name="com.feixiang.entity.sub"/>)
  • 若包扫描生成的别名与自定义别名冲突,后注册的会覆盖先注册的(取决于 XML 中的书写顺序)

易错场景/常见误区

误区错误表现正解
别名大小写不敏感导致误解认为 Employee 和 employee 是同一个别名MyBatis 别名区分大小写,Emp、emp、EMP 是三个不同的 key
包扫描时期望扫描子包子包下的类未被注册别名package 标签不递归扫描子包,需要为每个子包单独配置
对已注册的内置别名重复注册试图注册 string 为自定义类,导致类型混乱避免使用 MyBatis 内置别名作为自定义别名
省略 alias 属性时期望原类名以为 Employee 注册后别名还是 Employee省略 alias 时,默认别名为首字母小写的类名(employee)
在 typeAlias 的 type 属性写别名启动报 ClassNotFoundExceptiontype 属性必须写全限定类名,不能写别名

面试考点

Q1:MyBatis 有哪些常用的内置别名?

A:MyBatis 预先注册了大量常用类型的别名,例如:

  • 基本类型:_int → int,_long → long,_boolean → boolean,_double → double
  • 包装类型:int → Integer,long → Long,string → String,boolean → Boolean
  • 集合类型:map → Map,hashmap → HashMap,list → List,arraylist → ArrayList
  • 其他:date → Date,decimal → BigDecimal,object → Object 注意基本类型别名带下划线前缀(_int),以区别于包装类型(int)。

Q2:typeAlias 和 package 两种方式如何选择?

A:如果实体类数量少(少于 5 个)或需要自定义别名(如 Emp 代替 Employee),使用 typeAlias;如果实体类数量多且命名规范(遵循驼峰命名),使用 package 扫描更高效。实际项目中通常两者结合:对大部分实体用 package 扫描,对个别需要特殊别名的类用 typeAlias 补充。

Q3:包扫描时如何自定义某个类的别名而不修改全局配置?

A:在实体类上添加 @Alias("自定义名") 注解。例如 @Alias("Dept") 会让 TypeAliasRegistry 使用注解值而非首字母小写的类名。这种方式的好处是别名与代码在一起,修改时无需打开 XML 配置文件。


小结

typeAliases 是提升 Mapper XML 可读性的利器。通过 typeAlias 的精确控制和 package 的批量扫描,可以在简洁性与灵活性之间找到平衡。熟记内置别名清单能避免不必要的重复注册。建议团队约定实体包扫描路径,并在实体类上通过 @Alias 注解统一管理别名。


下一章引子

别名让 XML 变简洁了,但 Java 类型与 JDBC 类型之间的转换问题尚未触及。例如 Java 的 Date 如何存入 MySQL 的 DATETIME?自定义枚举如何映射到数据库的 TINYINT?这些转换工作由 typeHandlers 负责,它是 MyBatis 类型系统的"翻译官"。

上一页
settings
下一页
typeHandlers