mybatis全局配置文件
MyBatis 全局配置文件深度解析:从核心节点到工程实践
MyBatis 全局配置文件(默认命名为 mybatis-config.xml)是 MyBatis 框架的 “总开关”,用于配置数据库连接、映射规则、缓存策略、插件等核心参数。其配置节点有严格的顺序要求(必须按 properties→settings→typeAliases→typeHandlers→objectFactory→plugins→environments→databaseIdProvider→mappers 排列,乱序会导致解析报错),每个节点都承担特定职责。本文将逐一拆解每个节点的核心作用、配置方式、实际应用场景及工程最佳实践,帮助开发者掌握 MyBatis 配置的精髓。
根节点 <configuration>:配置入口
核心作用:作为所有配置节点的父容器,定义 MyBatis 的全局配置上下文。
关键规则:子节点必须按固定顺序排列(MyBatis 解析时会严格校验顺序,顺序错误会抛出
ConfigurationException)。示例结构:
<configuration> <!-- 子节点按固定顺序排列 --> <properties/> <settings/> <typeAliases/> <typeHandlers/> <objectFactory/> <plugins/> <environments/> <databaseIdProvider/> <mappers/> </configuration>
<properties>:属性配置(外部化配置)
核心作用
将数据库连接信息(如 URL、用户名、密码)、环境变量等外部化,避免硬编码在配置文件中,支持动态替换(如开发 / 测试 / 生产环境切换)。
三种配置方式与优先级
MyBatis 加载属性的优先级从低到高如下(高优先级覆盖低优先级):
- 子节点
<property>:直接在<properties>内定义的属性; - 外部配置文件:通过
resource(类路径)或url(网络 / 磁盘路径)引入的.properties文件; - 代码传参:构建
SqlSessionFactory时通过Properties对象传入的参数。
(1)方式 1:子节点 <property> 配置
<properties>
<!-- 直接定义属性,优先级最低 -->
<property name="jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbc.username" value="root"/>
</properties>
(2)方式 2:引入外部配置文件(推荐)
外部文件
src/main/resources/jdbc.properties:jdbc.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC jdbc.password=123456MyBatis 配置引用:
<properties resource="jdbc.properties"> <!-- 子节点属性会被外部文件覆盖(若同名) --> <property name="jdbc.username" value="dev_root"/> <!-- 最终生效为外部文件的 root --> </properties>
(3)方式 3:代码传参(优先级最高)
// 构建 SqlSessionFactory 时传入属性,覆盖外部配置
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
Properties props = new Properties();
props.put("jdbc.password", "prod_123456"); // 生产环境密码,覆盖外部文件的 123456
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is, props);
3. 高级特性:默认值与分隔符
通过配置属性启用默认值特性,避免因属性缺失导致启动失败:
<properties resource="jdbc.properties">
<!-- 1. 启用默认值特性(默认关闭) -->
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
<!-- 2. 自定义默认值分隔符(默认是 ":",可改为 "?:" 避免与 URL 中的 ":" 冲突) -->
<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/>
</properties>
<!-- 使用默认值:若 jdbc.password 未配置,默认使用 123456 -->
<dataSource type="POOLED">
<property name="password" value="${jdbc.password?:123456}"/>
</dataSource>
4. 工程实践
Spring Boot 整合:无需单独的jdbc.properties,直接引用application.yml中的配置:
# application.yml spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test username: root password: 123456MyBatis 可通过
${spring.datasource.url}直接引用 Spring 配置的属性。
<settings>:核心功能开关(重中之重)
<settings> 是 MyBatis 最核心的配置节点,用于覆盖 MyBatis 的默认行为,控制缓存、延迟加载、驼峰映射等关键功能。以下筛选最常用且影响最大的配置项详细说明:
| 配置名 | 核心作用 | 有效值 | 默认值 | 工程建议 |
|---|---|---|---|---|
cacheEnabled |
全局开启 / 关闭二级缓存(一级缓存默认开启,不受此配置影响) | true/false | true | 生产环境建议开启,提升查询性能;高频写场景可关闭 |
lazyLoadingEnabled |
全局开启延迟加载(关联对象(如 User 的 Orders)仅在访问时加载) | true/false | false | 关联查询多的场景(如订单查用户)建议开启,减少冗余加载 |
aggressiveLazyLoading |
开启后,访问任意属性会加载所有延迟关联;关闭后仅按需加载(3.4.1+ 默认 false) | true/false | false(3.4.1+) | 始终关闭,避免加载不必要的关联数据 |
mapUnderscoreToCamelCase |
自动将数据库下划线命名(如 user_name)映射为 Java 驼峰命名(userName) |
true/false | false | 强制开启,减少 resultMap 的配置量 |
logImpl |
指定日志实现(打印 SQL 语句,便于调试) | SLF4J/LOG4J/STDOUT_LOGGING | 未设置 | 开发环境用 STDOUT_LOGGING(控制台打印),生产用 SLF4J(结合 Logback) |
defaultExecutorType |
配置默认执行器(SIMPLE:普通;REUSE:复用 PreparedStatement;BATCH:批量) | SIMPLE/REUSE/BATCH | SIMPLE | 批量插入 / 更新场景用 BATCH,提升性能;普通场景用 SIMPLE |
useGeneratedKeys |
允许 JDBC 自动生成主键(支持 MySQL 自增、Oracle 序列) | true/false | false | 强制开启,配合 keyProperty 获取自增主键(如插入后返回用户 ID) |
配置示例(生产环境常用)
<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 关闭激进延迟加载,按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 开启驼峰自动映射(user_name → userName) -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 控制台打印 SQL(开发环境) -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 允许自动生成主键 -->
<setting name="useGeneratedKeys" value="true"/>
<!-- 批量操作时用 BATCH 执行器 -->
<setting name="defaultExecutorType" value="BATCH"/>
</settings>
<typeAliases>:类型别名(简化配置)
核心作用
为 Java 类的全类名定义简短别名,在 resultType、parameterType 等配置中替代全类名,减少冗余,提升可读性。
两种配置方式
(1)方式 1:单个类配置(typeAlias)
<typeAliases>
<!-- type:全类名;alias:自定义别名(大小写不敏感) -->
<typeAlias type="com.example.pojo.User" alias="MyUser"/>
</typeAliases>
<!-- 使用别名:resultType 直接用 MyUser -->
<select id="getUserById" resultType="MyUser">
SELECT * FROM t_user WHERE id = #{id}
</select>
(2)方式 2:批量包扫描(推荐)
为指定包下的所有类自动生成别名,默认别名为类名首字母小写(如 User → user):
<typeAliases>
<!-- 扫描 com.example.pojo 包下所有类 -->
<package name="com.example.pojo"/>
</typeAliases>
<!-- 使用默认别名:resultType 用 user -->
<select id="getUserById" resultType="user">
SELECT * FROM t_user WHERE id = #{id}
</select>
(3)方式 3:注解自定义别名(@Alias)
在 Java 类上用 @Alias 注解自定义别名,优先级高于包扫描的默认规则:
// 注解定义别名,覆盖默认的 "user"
public class User {
private Long id;
private String userName;
// getter/setter
}
<!-- 使用注解别名 -->
<select id="getUserById" resultType="CustomerUser">
SELECT * FROM t_user WHERE id = #{id}
</select>
系统内置别名
MyBatis 为常用 Java 类型预定义了别名(无需配置即可使用),例如:
- 基本类型:
int→_int,long→_long; - 包装类型:
Integer→integer,Long→long; - 集合类型:
List→list,Map→map; - 时间类型:
Date→date,LocalDateTime→localdatetime。
示例:
<!-- 使用内置别名:resultType 为 list(对应 List),泛型为 user -->
<select id="getAllUsers" resultType="list">
SELECT * FROM t_user
</select>
<typeHandlers>:类型处理器(数据类型转换)
核心作用
负责 Java 类型(JavaType) 与 JDBC 类型(JdbcType) 之间的转换:
- 入参转换:将 Java 对象的参数(如
String)转换为 JDBC 支持的类型(如VARCHAR),用于PreparedStatement.setXXX(); - 结果转换:将数据库返回的 JDBC 类型(如
INT)转换为 Java 对象(如Integer),用于ResultSet.getXXX()。
系统内置类型处理器
MyBatis 为绝大多数常用类型提供了默认处理器(无需配置),例如:
StringTypeHandler:String↔VARCHAR;IntegerTypeHandler:Integer↔INTEGER;LocalDateTimeTypeHandler:LocalDateTime↔TIMESTAMP。
自定义类型处理器(实战场景)
当内置处理器无法满足需求时(如枚举、JSON 类型),需自定义处理器。以下以 MySQL JSON 字段映射到 Java Map 为例:
(1)自定义 TypeHandler
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import com.alibaba.fastjson.JSONObject;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
// 1. 注解指定映射的 JavaType 和 JdbcType
// Java 类型:Map
// JDBC 类型:MySQL 的 JSON 字段在 JDBC 中映射为 VARCHAR
public class MapJsonTypeHandler extends BaseTypeHandler<Map<String, Object>> {
// 2. 入参转换:Java Map → JSON 字符串
public void setNonNullParameter(PreparedStatement ps, int i, Map<String, Object> parameter, JdbcType jdbcType) throws SQLException {
String jsonStr = JSONObject.toJSONString(parameter);
ps.setString(i, jsonStr);
}
// 3. 结果转换:JSON 字符串 → Java Map(按列名)
public Map<String, Object> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String jsonStr = rs.getString(columnName);
return jsonStr == null ? null : JSONObject.parseObject(jsonStr, Map.class);
}
// 4. 结果转换:JSON 字符串 → Java Map(按列索引)
public Map<String, Object> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String jsonStr = rs.getString(columnIndex);
return jsonStr == null ? null : JSONObject.parseObject(jsonStr, Map.class);
}
// 5. 存储过程结果转换
public Map<String, Object> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String jsonStr = cs.getString(columnIndex);
return jsonStr == null ? null : JSONObject.parseObject(jsonStr, Map.class);
}
}
(2)注册自定义处理器
<typeHandlers>
<typeHandler handler="com.example.handler.MapJsonTypeHandler"/>
</typeHandlers>
(3)使用示例
数据库表:
t_user有ext_info字段(类型为 JSON);Mapper XML:
<insert id="insertUser"> INSERT INTO t_user (user_name, ext_info) VALUES (#{userName}, #{extInfo, typeHandler=com.example.handler.MapJsonTypeHandler}) </insert> <select id="getUserById" resultType="user"> SELECT id, user_name, ext_info FROM t_user WHERE id = #{id} <!-- 结果自动通过 MapJsonTypeHandler 转换为 Map --> </select>
<plugins>:插件(扩展 MyBatis 功能)
核心作用
通过拦截 MyBatis 的核心组件(Executor、ParameterHandler、ResultSetHandler、StatementHandler),实现自定义逻辑,如分页、日志、性能监控等。
插件开发原理
插件需实现 org.apache.ibatis.plugin.Interceptor 接口,并通过 @Intercepts 注解指定拦截的组件和方法:
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.Properties;
// 1. 指定拦截的组件和方法:拦截 Executor 的 query 方法
public class QueryLogPlugin implements Interceptor {
// 2. 拦截逻辑:执行 query 方法前打印 SQL 日志
public Object intercept(Invocation invocation) throws Throwable {
// 获取拦截的方法参数(MappedStatement 包含 SQL 信息)
Object[] args = invocation.getArgs();
org.apache.ibatis.mapping.MappedStatement ms = (org.apache.ibatis.mapping.MappedStatement) args[0];
System.out.println("执行 SQL:" + ms.getSqlSource().getBoundSql(args[1]).getSql());
// 执行原方法(放行)
return invocation.proceed();
}
// 3. 生成代理对象(MyBatis 内部调用)
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
// 4. 设置插件属性(从 XML 配置中读取)
public void setProperties(Properties properties) {
// 例如读取配置的 logLevel:properties.getProperty("logLevel")
}
}
注册插件
<plugins>
<plugin interceptor="com.example.plugin.QueryLogPlugin">
<!-- 配置插件属性(可选) -->
<property name="logLevel" value="INFO"/>
</plugin>
</plugins>
常用第三方插件
PageHelper:MyBatis 最流行的分页插件,支持 MySQL、Oracle 等多种数据库的分页查询;
配置示例:
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 配置数据库方言 -->
<property name="helperDialect" value="mysql"/>
<!-- 支持 PageHelper.startPage() 自动分页 -->
<property name="supportMethodsArguments" value="true"/>
</plugin>
</plugins>
- MyBatis-Plus:基于 MyBatis 的增强工具,内置分页、CRUD 接口等功能,无需编写 XML。
<environments>:环境配置(多数据源支持)
核心作用
配置数据库连接环境(如开发、测试、生产),每个环境包含 事务管理器 和 数据源 两部分。MyBatis 允许配置多个环境,但每个 SqlSessionFactory 只能选择一个环境。
关键配置项
(1)事务管理器(transactionManager)
MyBatis 提供两种事务管理器:
JDBC:依赖 JDBC 的事务管理(java.sql.Connection的 commit/rollback),适用于独立使用 MyBatis 的场景;MANAGED:依赖外部容器(如 Spring、Java EE)管理事务,MyBatis 不干预事务提交 / 回滚,适用于 Spring 整合场景。
示例:
<transactionManager type="JDBC"/> <!-- 独立使用 MyBatis -->
<!-- <transactionManager type="MANAGED"/> --> <!-- Spring 整合时使用 -->
(2)数据源(dataSource)
MyBatis 提供三种数据源类型:
| 类型 | 核心特点 | 适用场景 |
|---|---|---|
UNPOOLED |
无连接池,每次请求创建 / 关闭连接 | 开发环境、低并发场景 |
POOLED |
内置连接池,复用连接,提升性能 | 生产环境、中低并发场景 |
JNDI |
从 JNDI 容器获取数据源(如 Tomcat 的数据源) | Java EE 容器环境 |
生产环境推荐:使用第三方连接池(如 Druid、HikariCP)替代 MyBatis 内置数据源,性能更优。以下是整合 Druid 的示例:
引入 Druid 依赖(Maven):
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.20</version> </dependency>配置 Druid 数据源:
<dataSource type="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- Druid 连接池参数 --> <property name="maxActive" value="20"/> <!-- 最大活跃连接数 --> <property name="minIdle" value="5"/> <!-- 最小空闲连接数 --> <property name="maxWait" value="60000"/> <!-- 获取连接超时时间(毫秒) --> <property name="validationQuery" value="SELECT 1"/> <!-- 连接校验 SQL --> </dataSource>
多环境配置示例
<environments default="development">
<!-- 开发环境 -->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${dev.jdbc.driver}"/>
<property name="url" value="${dev.jdbc.url}"/>
<property name="username" value="${dev.jdbc.username}"/>
<property name="password" value="${dev.jdbc.password}"/>
</dataSource>
</environment>
<!-- 生产环境 -->
<environment id="production">
<transactionManager type="MANAGED"/> <!-- Spring 管理事务 -->
<dataSource type="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prod.jdbc.driver}"/>
<property name="url" value="${prod.jdbc.url}"/>
<property name="username" value="${prod.jdbc.username}"/>
<property name="password" value="${prod.jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 构建 SqlSessionFactory 时指定生产环境 -->
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is, "production");
<databaseIdProvider>:多数据库适配
核心作用
根据数据库厂商(如 MySQL、Oracle)自动选择对应的 SQL 语句,解决多数据库兼容问题(如分页语法差异)。
配置示例
(1)配置数据库标识
<databaseIdProvider type="DB_VENDOR">
<!-- name:DatabaseMetaData.getDatabaseProductName() 返回的厂商名(如 "MySQL"、"Oracle") -->
<!-- value:自定义别名,用于 mapper.xml 中的 databaseId 属性 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
(2)Mapper XML 中适配多数据库
<!-- MySQL 分页:使用 LIMIT -->
<select id="getUserList" resultType="user" databaseId="mysql">
SELECT * FROM t_user LIMIT #{offset}, #{pageSize}
</select>
<!-- Oracle 分页:使用 ROWNUM -->
<select id="getUserList" resultType="user" databaseId="oracle">
SELECT * FROM (
SELECT u.*, ROWNUM rn FROM t_user u WHERE ROWNUM <= #{offset} + #{pageSize}
) WHERE rn > #{offset}
</select>
<!-- 通用 SQL:无 databaseId,当没有匹配的数据库标识时使用 -->
<select id="getUserById" resultType="user">
SELECT * FROM t_user WHERE id = #{id}
</select>
匹配规则
MyBatis 加载 SQL 语句的优先级:
- 优先加载
databaseId与当前数据库标识一致的语句; - 若未找到,加载无
databaseId的语句; - 若同时存在带
databaseId和不带的语句,不带的会被舍弃。
<mappers>:映射器注册(关联 Mapper 接口与 XML)
核心作用
将 Mapper 接口(如 UserMapper.java)与 SQL 映射文件(如 UserMapper.xml)注册到 MyBatis,确保 MyBatis 能找到并执行 SQL 语句。
四种注册方式
| 方式 | 配置语法 | 注意事项 |
|---|---|---|
| resource | <mapper resource="mapper/UserMapper.xml"/> |
基于类路径(src/main/resources),推荐用于 XML 映射文件;路径用 / 分隔。 |
| url | <mapper url="file:///D:/mapper/UserMapper.xml"/> |
基于磁盘 / 网络路径,需指定完整 URL(如 file:、http:),不推荐工程使用。 |
| class | <mapper class="com.example.mapper.UserMapper"/> |
基于 Mapper 接口: 1. 接口与 XML 需同名且同路径; 2. 若用注解(如 @Select),可无 XML。 |
| package | <package name="com.example.mapper"/> |
批量注册包下所有 Mapper 接口: 1. 接口与 XML 需同名且同路径; 2. 最常用,简化配置。 |
工程实践(Spring Boot 整合)
Spring Boot 中无需在 mybatis-config.xml 中注册 Mapper,直接通过注解扫描:
// 启动类添加 @MapperScan,批量扫描 Mapper 接口
// 扫描 com.example.mapper 包下所有接口
public class MyBatisApplication {
public static void main(String[] args) {
SpringApplication.run(MyBatisApplication.class, args);
}
}
常见问题排查
- Mapper 接口未注册:报错No qualifying bean of type ‘com.example.mapper.UserMapper’ available,检查:
@MapperScan扫描路径是否正确;- Mapper 接口是否加了
@Mapper注解(若未用@MapperScan); - 接口与 XML 是否同名且同路径。
总结:全局配置文件工程最佳实践
- 配置顺序不可乱:严格按
properties→settings→typeAliases→...→mappers排列; - 外部化配置优先:数据库信息用外部文件(如
application.yml),避免硬编码; - 关键 settings 必配:
mapUnderscoreToCamelCase、useGeneratedKeys、logImpl等强制开启,提升开发效率; - 批量注册 Mapper:用
<package>或@MapperScan批量注册,减少配置量; - 生产环境用第三方连接池: Druid 或 HikariCP 替代 MyBatis 内置数据源,提升性能;
- 多数据库适配:用
databaseIdProvider解决 SQL 语法差异,避免分支代码