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

    • 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执行器类型
    • 分页插件

properties

导学

本节学习目标:

  • 理解 properties 元素在 MyBatis 全局配置文件中的定位与作用
  • 掌握外部 .properties 文件引入的两种方式(resource 与 url)
  • 弄清 Java 代码传入 Properties、外部文件、配置文件内嵌属性三者的优先级关系
  • 能够在实际项目中正确运用 ${...} 占位符实现配置外部化

定义

在 MyBatis 全局配置文件 mybatis-config.xml 中,数据库连接信息(驱动、URL、用户名、密码)如果直接写死,会导致:

  • 不同环境(开发、测试、生产)需要维护多份 XML 文件
  • 密码等敏感信息暴露在版本控制中
  • 运维人员修改配置必须重新打包应用

properties 元素的核心使命是引入外部属性文件,实现配置外部化,让 XML 中可以使用 ${driver}、${url} 等占位符,从而将易变配置抽离到外部文件或通过 Java 代码动态注入。


适用位置与核心属性

properties 必须是 mybatis-config.xml 中第一个子元素(MyBatis 3.5.x 的 DTD 约束)。

属性是否必填说明
resource与 url 二选一从类路径(classpath)加载属性文件,如 db.properties
url与 resource 二选一从绝对 URL 加载属性文件,如 file:///opt/config/db.properties

此外,还可以在 properties 标签体内直接定义若干 property 子标签:

<properties resource="db.properties">
  <property name="username" value="root"/>
</properties>

核心原理

配置加载优先级流程

MyBatis 在解析 properties 时,会按照严格优先级合并三处来源的属性,高优先级覆盖低优先级:

优先级从高到低:

  1. Java 代码中通过 SqlSessionFactoryBuilder.build(inputStream, properties) 传入的 Properties
  2. resource 或 url 指向的外部 .properties 文件
  3. properties 标签体内嵌的 property 子标签

源码层面:MyBatis 使用 XMLConfigBuilder.propertiesElement(XNode) 方法完成上述合并逻辑,最终存储在 Configuration 对象的 variables 字段中。


完整示例

场景说明

乐途公司员工管理系统需要连接 MySQL 5.7 数据库 employee_db。开发环境、测试环境的数据库密码不同,要求将连接配置抽离到外部文件,同时演示 Java 代码动态覆盖密码的场景。

操作前的状态

项目目录结构:

src/main/resources/
├── mybatis-config.xml
└── db.properties

db.properties 内容:

# 乐途公司员工数据库配置
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/employee_db?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
username=root
password=dev_password_123

完整配置代码

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">
    <!-- 内嵌属性,优先级最低,仅作为默认值 -->
    <property name="username" value="fallback_user"/>
  </properties>

  <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"/>
  </mappers>

</configuration>

Java 代码动态覆盖(生产环境传入真实密码):

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;
import java.util.Properties;

public class MyBatisBootstrap {
    public static void main(String[] args) throws Exception {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

        // 动态覆盖:最高优先级
        Properties props = new Properties();
        props.setProperty("password", "prod_secret_456");

        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                .build(inputStream, props);

        System.out.println("SqlSessionFactory 创建成功,密码已被动态覆盖");
    }
}

实际效果/结果

运行后,MyBatis 实际使用的连接参数为:

参数最终值来源说明
drivercom.mysql.cj.jdbc.Driverdb.properties
urljdbc:mysql://localhost:3306/employee_db?...db.properties
usernamerootdb.properties(覆盖内嵌默认值)
passwordprod_secret_456Java 代码传入,最高优先级

控制台输出:

SqlSessionFactory 创建成功,密码已被动态覆盖

分析

  • ${driver} 等占位符在 XMLConfigBuilder 解析阶段被替换为真实值
  • 若 db.properties 中缺少某个 key,而 XML 内嵌标签有定义,则回退到内嵌值
  • 若三处都未定义,MyBatis 不会报错,而是将 ${xxx} 原样保留,最终在创建连接时失败

易错场景/常见误区

误区错误表现正解
properties 放错位置将 properties 写在 environments 之后,启动报 DTD 约束错误properties 必须是 configuration 的第一个子元素
占位符拼写错误写成 ${dirver},启动不报错但连接时提示 No suitable driver found仔细核对 .properties 文件中的 key 名与 XML 中 ${} 内名称完全一致
认为 XML 内嵌属性优先级最高内嵌属性被外部文件覆盖,导致使用了错误的用户名记住优先级:Java 代码 > 外部文件 > 内嵌属性
使用 url 属性时写相对路径url="db.properties" 找不到文件url 要求绝对路径(file:/// 或 http://),相对路径请用 resource
外部文件编码问题中文注释导致解析乱码,属性值读取错误统一使用 UTF-8 编码保存 .properties 文件

面试考点

Q1:MyBatis 中 properties 元素的加载优先级是怎样的?

A:从高到低依次为:① Java 代码通过 SqlSessionFactoryBuilder.build() 传入的 Properties 对象;② resource 或 url 引入的外部 .properties 文件;③ properties 标签体内嵌的 property 子标签。高优先级覆盖低优先级。

Q2:如果 ${password} 在三处都没有定义,MyBatis 会报错吗?

A:解析阶段不会报错,XMLConfigBuilder 会原样保留 ${password} 字符串。直到 dataSource 创建连接时,由于密码为 ${password} 而导致连接失败,此时才会抛出异常。因此建议在启动后打印关键配置做校验。

Q3:resource 和 url 有什么区别?

A:resource 从类路径(classpath)加载,适合打包在 jar 内的配置文件;url 从绝对 URL 加载,适合配置文件放在服务器固定目录或远程 HTTP 地址的场景。日常开发推荐 resource。


小结

properties 是 MyBatis 全局配置文件的"入口第一站",它通过外部化配置解决了环境差异与敏感信息暴露的问题。掌握三处来源的优先级顺序,是避免配置被意外覆盖的关键。配合 ${...} 占位符,可以让 mybatis-config.xml 成为一份与环境无关的"纯净模板"。


下一章引子

配置外部化之后,MyBatis 的行为还受大量全局开关控制——比如是否开启二级缓存、是否开启驼峰映射、是否使用 JDBC 自动生成主键。这些开关全部集中在 settings 元素中,它是影响 MyBatis 运行时的"总控面板"。接下来,我们将逐一拆解这些关键设置。

上一页
本章定位
下一页
settings