核心配置
MyBatis 的核心配置文件 mybatis-config.xml 包含了影响 MyBatis 行为的各类配置。本章将详细介绍各个配置元素的作用和使用方法。
配置文件结构
MyBatis 配置文件有严格的顺序要求,必须按照以下顺序配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 1. properties - 属性配置 -->
<properties/>
<!-- 2. settings - 全局设置 -->
<settings/>
<!-- 3. typeAliases - 类型别名 -->
<typeAliases/>
<!-- 4. typeHandlers - 类型处理器 -->
<typeHandlers/>
<!-- 5. objectFactory - 对象工厂 -->
<objectFactory/>
<!-- 6. objectWrapperFactory - 对象包装工厂 -->
<objectWrapperFactory/>
<!-- 7. reflectorFactory - 反射工厂 -->
<reflectorFactory/>
<!-- 8. plugins - 插件 -->
<plugins/>
<!-- 9. environments - 环境配置 -->
<environments/>
<!-- 10. databaseIdProvider - 数据库厂商标识 -->
<databaseIdProvider/>
<!-- 11. mappers - 映射器 -->
<mappers/>
</configuration>
properties 元素
properties 元素用于外部化配置,可以从属性文件或子元素中加载配置值。
从属性文件加载
# db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_demo
jdbc.username=root
jdbc.password=123456
<configuration>
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<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>
</configuration>
从子元素配置
<properties>
<property name="jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/mybatis_demo"/>
</properties>
优先级
当同一属性在多处定义时,优先级从高到低:
- 方法参数传递的属性
- resource/url 加载的属性
- properties 元素内的 property 子元素
settings 元素
settings 是 MyBatis 中极为重要的调整设置,会改变 MyBatis 的运行时行为。
常用设置项
<settings>
<!-- 开启驼峰命名自动映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启全局二级缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 延迟加载全局开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 积极加载(false 按需加载) -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 允许 JDBC 支持自动生成主键 -->
<setting name="useGeneratedKeys" value="true"/>
<!-- 使用列标签代替列名 -->
<setting name="useColumnLabel" value="true"/>
<!-- 开启自动映射 -->
<setting name="autoMappingBehavior" value="PARTIAL"/>
<!-- 配置默认的执行器 -->
<setting name="defaultExecutorType" value="SIMPLE"/>
<!-- 设置超时时间 -->
<setting name="defaultStatementTimeout" value="25"/>
<!-- 允许在嵌套语句中使用分页 -->
<setting name="safeRowBoundsEnabled" value="false"/>
<!-- 开启自动驼峰命名规则映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 本地缓存作用域 -->
<setting name="localCacheScope" value="SESSION"/>
<!-- 当没有为参数指定 JDBC 类型时,空值的默认 JDBC 类型 -->
<setting name="jdbcTypeForNull" value="OTHER"/>
<!-- 指定触发延迟加载的方法 -->
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
设置项详解
| 设置项 | 说明 | 默认值 | 可选值 |
|---|---|---|---|
cacheEnabled | 全局开启二级缓存 | true | true/false |
lazyLoadingEnabled | 延迟加载开关 | false | true/false |
aggressiveLazyLoading | 积极加载 | false (3.4.1+) | true/false |
multipleResultSetsEnabled | 允许单条语句返回多结果集 | true | true/false |
useColumnLabel | 使用列标签代替列名 | true | true/false |
useGeneratedKeys | 允许 JDBC 自动生成主键 | false | true/false |
autoMappingBehavior | 自动映射行为 | PARTIAL | NONE/PARTIAL/FULL |
autoMappingUnknownColumnBehavior | 自动映射未知列行为 | NONE | NONE/WARNING/FAILING |
defaultExecutorType | 默认执行器 | SIMPLE | SIMPLE/REUSE/BATCH |
defaultStatementTimeout | 超时时间 | null | 正整数 |
defaultFetchSize | 获取数量 | null | 正整数 |
defaultResultSetType | 结果集类型 | null | FORWARD_ONLY/SCROLL_SENSITIVE/SCROLL_INSENSITIVE |
safeRowBoundsEnabled | 允许嵌套语句分页 | false | true/false |
safeResultHandlerEnabled | 允许嵌套语句结果处理 | true | true/false |
mapUnderscoreToCamelCase | 驼峰命名映射 | false | true/false |
localCacheScope | 本地缓存作用域 | SESSION | SESSION/STATEMENT |
jdbcTypeForNull | 空值 JDBC 类型 | OTHER | NULL/VARCHAR/OTHER |
lazyLoadTriggerMethods | 延迟加载触发方法 | equals,clone,hashCode,toString | 方法名列表 |
callSettersOnNulls | 空值调用 setter | false | true/false |
returnInstanceForEmptyRow | 空行返回实例 | false | true/false |
logPrefix | 日志前缀 | null | 字符串 |
logImpl | 日志实现 | null | SLF4J/LOG4J/LOG4J2/JDK_LOGGING/COMMONS_LOGGING/STDOUT_LOGGING/NO_LOGGING |
proxyFactory | 代理工厂 | JAVASSIST | CGLIB/JAVASSIST |
vfsImpl | VFS 实现 | null | 类全限定名 |
useActualParamName | 使用实际参数名 | true | true/false |
configurationFactory | 配置工厂 | null | 类全限定名 |
执行器类型
- SIMPLE:普通执行器,每次执行创建新的 Statement
- REUSE:重用执行器,会重用 Statement
- BATCH:批量执行器,重用 Statement 并批量执行
typeAliases 元素
类型别名是为 Java 类型设置一个缩写名字,减少类全限定名的冗余。
配置方式
<typeAliases>
<!-- 单个别名配置 -->
<typeAlias type="com.example.mybatis.entity.User" alias="User"/>
<!-- 包扫描配置(推荐) -->
<package name="com.example.mybatis.entity"/>
</typeAliases>
使用注解配置别名
@Alias("user")
public class User {
// ...
}
内置类型别名
MyBatis 为常见的 Java 类型内置了别名:
| 别名 | 映射类型 |
|---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
typeHandlers 元素
类型处理器用于 Java 类型和 JDBC 类型之间的转换。
内置类型处理器
MyBatis 内置了大量的类型处理器:
| 类型处理器 | Java 类型 | JDBC 类型 |
|---|---|---|
BooleanTypeHandler | Boolean | BOOLEAN |
ByteTypeHandler | Byte | NUMERIC/SMALLINT |
ShortTypeHandler | Short | NUMERIC/SMALLINT |
IntegerTypeHandler | Integer | NUMERIC/INTEGER |
LongTypeHandler | Long | NUMERIC/BIGINT |
FloatTypeHandler | Float | NUMERIC/FLOAT |
DoubleTypeHandler | Double | NUMERIC/DOUBLE |
StringTypeHandler | String | CHAR/VARCHAR |
DateTypeHandler | Date | TIMESTAMP |
LocalDateTimeTypeHandler | LocalDateTime | TIMESTAMP |
LocalDateTypeHandler | LocalDate | DATE |
LocalTimeTypeHandler | LocalTime | TIME |
自定义类型处理器
当内置处理器不能满足需求时,可以自定义:
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}
配置自定义类型处理器:
<typeHandlers>
<typeHandler handler="com.example.mybatis.handler.ExampleTypeHandler"/>
<!-- 或者包扫描 -->
<package name="com.example.mybatis.handler"/>
</typeHandlers>
枚举类型处理器
MyBatis 提供了两种枚举处理器:
public enum Status {
ENABLED(1, "启用"),
DISABLED(0, "禁用");
private final int code;
private final String desc;
Status(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() { return code; }
public String getDesc() { return desc; }
}
<!-- 使用序号存储 -->
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
javaType="com.example.mybatis.enums.Status"/>
<!-- 使用名称存储 -->
<typeHandler handler="org.apache.ibatis.type.EnumTypeHandler"
javaType="com.example.mybatis.enums.Status"/>
plugins 元素
MyBatis 允许在映射语句执行过程中的某一点进行拦截调用。
可拦截的方法
自定义插件示例
@Intercepts({
@Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)
})
public class ExamplePlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 前置处理
long start = System.currentTimeMillis();
// 执行原方法
Object result = invocation.proceed();
// 后置处理
long end = System.currentTimeMillis();
System.out.println("SQL 执行耗时: " + (end - start) + "ms");
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 设置属性
}
}
配置插件:
<plugins>
<plugin interceptor="com.example.mybatis.plugin.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
environments 元素
MyBatis 可以配置多种环境,每个环境对应一个数据库配置。
多环境配置
<environments default="development">
<!-- 开发环境 -->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${dev.driver}"/>
<property name="url" value="${dev.url}"/>
<property name="username" value="${dev.username}"/>
<property name="password" value="${dev.password}"/>
</dataSource>
</environment>
<!-- 测试环境 -->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${test.driver}"/>
<property name="url" value="${test.url}"/>
<property name="username" value="${test.username}"/>
<property name="password" value="${test.password}"/>
</dataSource>
</environment>
<!-- 生产环境 -->
<environment id="production">
<transactionManager type="MANAGED"/>
<dataSource type="JNDI">
<property name="data_source" value="java:comp/env/jdbc/MyDataSource"/>
</dataSource>
</environment>
</environments>
事务管理器
| 类型 | 说明 |
|---|---|
JDBC | 使用 JDBC 的提交和回滚设置,依赖从数据源获取的连接来管理事务 |
MANAGED | 让容器来管理事务的整个生命周期,默认情况下会关闭连接 |
数据源类型
| 类型 | 说明 |
|---|---|
UNPOOLED | 每次请求时打开和关闭连接,不使用连接池 |
POOLED | 使用连接池,复用连接,提高性能 |
JNDI | 通过 JNDI 获取数据源,用于 EJB 或应用服务器 |
POOLED 数据源配置
<dataSource type="POOLED">
<!-- 基础配置 -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<!-- 连接池配置 -->
<property name="poolMaximumActiveConnections" value="10"/>
<property name="poolMaximumIdleConnections" value="5"/>
<property name="poolMaximumCheckoutTime" value="20000"/>
<property name="poolTimeToWait" value="20000"/>
<property name="poolPingQuery" value="SELECT 1"/>
<property name="poolPingEnabled" value="true"/>
<property name="poolPingConnectionsNotUsedFor" value="3600000"/>
</dataSource>
| 属性 | 说明 | 默认值 |
|---|---|---|
poolMaximumActiveConnections | 最大活动连接数 | 10 |
poolMaximumIdleConnections | 最大空闲连接数 | 5 |
poolMaximumCheckoutTime | 获取连接最长等待时间 | 20000ms |
poolTimeToWait | 等待获取连接的时间 | 20000ms |
poolPingQuery | 检测连接是否有效的 SQL | 无 |
poolPingEnabled | 是否启用连接检测 | false |
poolPingConnectionsNotUsedFor | 检测间隔时间 | 0 |
databaseIdProvider 元素
用于支持多数据库厂商,根据不同数据库执行不同的 SQL。
配置
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle"/>
<property name="MySQL" value="mysql"/>
<property name="PostgreSQL" value="postgresql"/>
</databaseIdProvider>
使用
<select id="selectById" resultType="User" databaseId="mysql">
SELECT * FROM user WHERE id = #{id}
</select>
<select id="selectById" resultType="User" databaseId="oracle">
SELECT * FROM user WHERE id = #{id}
</select>
mappers 元素
告诉 MyBatis 到哪里去找映射文件。
配置方式
<mappers>
<!-- 使用相对于类路径的资源引用 -->
<mapper resource="com/example/mybatis/mapper/UserMapper.xml"/>
<!-- 使用完全限定资源定位符(URL) -->
<mapper url="file:///var/mappers/UserMapper.xml"/>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mapper class="com.example.mybatis.mapper.UserMapper"/>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<package name="com.example.mybatis.mapper"/>
</mappers>
推荐配置
使用包扫描方式最简洁:
<mappers>
<package name="com.example.mybatis.mapper"/>
</mappers>
注意:使用包扫描时,XML 文件必须与接口在同一包路径下。
完整配置示例
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 属性配置 -->
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
<!-- 全局设置 -->
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="30"/>
<setting name="logImpl" value="SLF4J"/>
</settings>
<!-- 类型别名 -->
<typeAliases>
<package name="com.example.mybatis.entity"/>
</typeAliases>
<!-- 类型处理器 -->
<typeHandlers>
<package name="com.example.mybatis.handler"/>
</typeHandlers>
<!-- 插件 -->
<plugins>
<plugin interceptor="com.example.mybatis.plugin.SqlLogPlugin"/>
</plugins>
<!-- 环境配置 -->
<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}"/>
<property name="poolMaximumActiveConnections" value="20"/>
<property name="poolPingEnabled" value="true"/>
</dataSource>
</environment>
</environments>
<!-- 数据库厂商标识 -->
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
</databaseIdProvider>
<!-- 映射器 -->
<mappers>
<package name="com.example.mybatis.mapper"/>
</mappers>
</configuration>
小结
本章详细介绍了 MyBatis 核心配置文件的各个元素:
- properties:外部化配置管理
- settings:全局行为设置
- typeAliases:类型别名简化
- typeHandlers:类型转换处理
- plugins:插件扩展机制
- environments:多环境配置
- databaseIdProvider:多数据库支持
- mappers:映射器注册
下一章将介绍 XML 映射器的详细用法。