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

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

不使用 XML 构建 SqlSessionFactory

概述

MyBatis 提供两套并行的配置路径来构建 SqlSessionFactory:基于 XML 配置文件 的传统方式,和基于 Java 代码 的纯编程方式。两种方式完全等价,选择取决于项目阶段和个人偏好。本节将对比两种路径,帮助你做出合适选择。

两种构建路径对比

路径一:XML 方式(传统)

这是 MyBatis 官方推荐的生产环境配置方式。通过 mybatis-config.xml 集中管理数据源、事务、映射器等配置。

// 1. 读取 XML 配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);

// 2. 构建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
    new SqlSessionFactoryBuilder().build(inputStream);

对应的 mybatis-config.xml:

<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/feixiang"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="org/feixiang/mapper/EmployeeMapper.xml"/>
    </mappers>
</configuration>

路径二:Java 代码方式(纯编程)

完全用 Java 代码替代 XML,适合快速原型开发和单元测试。

// 1. 创建数据源
DataSource dataSource = new PooledDataSource(
    "com.mysql.cj.jdbc.Driver",
    "jdbc:mysql://localhost:3306/feixiang",
    "root",
    "123456"
);

// 2. 创建事务工厂
TransactionFactory transactionFactory = new JdbcTransactionFactory();

// 3. 组装环境
Environment environment = new Environment("development",
    transactionFactory, dataSource);

// 4. 构建 Configuration
Configuration configuration = new Configuration(environment);
configuration.addMapper(EmployeeMapper.class);

// 5. 构建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
    new SqlSessionFactoryBuilder().build(configuration);

流程对比图

实战场景:飞翔科技公司员工管理系统

场景介绍

飞翔科技公司由技术总监大翔带领团队开发内部员工管理系统。团队分工如下:

角色成员职责
技术总监大翔架构决策,确定生产用 XML 配置
高级开发白歌编写核心 Mapper XML
后端开发孔蓝实现 Service 层
初级开发小崔编写单元测试
测试工程师黄俪集成测试验证

场景一:小崔写单元测试(Java 代码方式)

小崔需要为 EmployeeMapper 写单元测试,不想依赖外部 XML 配置文件,于是用 Java 代码方式快速搭建测试环境:

public class EmployeeMapperTest {

    private SqlSessionFactory sqlSessionFactory;

    @BeforeEach
    public void setUp() {
        // 使用 H2 内存数据库,无需外部依赖
        DataSource dataSource = new PooledDataSource(
            "org.h2.Driver",
            "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1",
            "sa",
            ""
        );

        TransactionFactory txFactory = new JdbcTransactionFactory();
        Environment env = new Environment("test", txFactory, dataSource);
        Configuration config = new Configuration(env);

        // 直接注册 Mapper 接口
        config.addMapper(EmployeeMapper.class);

        sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);

        // 初始化表结构
        try (SqlSession session = sqlSessionFactory.openSession()) {
            session.getConnection().createStatement().execute(
                "CREATE TABLE employee (id INT PRIMARY KEY, name VARCHAR(50), dept VARCHAR(50))"
            );
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void testFindById() {
        try (SqlSession session = sqlSessionFactory.openSession()) {
            EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
            // 先插入测试数据
            Employee emp = new Employee(1, "小崔", "研发部");
            mapper.insert(emp);
            session.commit();

            // 再验证查询
            Employee result = mapper.findById(1);
            assertEquals("小崔", result.getName());
        }
    }
}

关键点:configuration.addMapper(EmployeeMapper.class) 不仅注册了 Mapper 接口,MyBatis 还会自动去 classpath 下查找同名的 EmployeeMapper.xml 并加载。这意味着即使你用 Java 代码构建 Configuration,XML 映射文件仍然可以共存。

场景二:大翔的生产配置(XML 方式)

生产环境由大翔决定使用 XML 方式,方便运维统一管理数据库连接参数:

<!-- mybatis-config.xml -->
<configuration>
    <properties resource="db.properties"/>  <!-- 密码等敏感信息外置 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
    <environments default="production">
        <environment id="production">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="org/feixiang/mapper/EmployeeMapper.xml"/>
        <mapper resource="org/feixiang/mapper/DepartmentMapper.xml"/>
    </mappers>
</configuration>
# db.properties — 独立于代码的敏感配置
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://10.0.1.100:3306/feixiang_prod
db.username=feixiang_app
db.password=Prod@2026!

两种方式适用场景

维度Java 代码方式XML 配置方式
适用阶段单元测试、快速原型、Demo 演示生产部署、正式项目
配置修改需改代码重新编译改 XML 即可,部分支持热加载
环境切换代码中硬编码或手动传参<properties> 外置,切换配置文件即可
团队协作配置散落在 Java 类中,不易查找统一入口,运维友好
IDE 支持无语法提示、无校验有 Schema 约束和自动补全
复杂度上限可配置所有项但代码冗长结构清晰,适合复杂配置
推荐人群开发者自测、小崔这样的新手快速上手大翔这样的架构师做项目级决策

易错场景提醒

1. 忘记注册 Mapper

// ❌ 错误:只创建了 Configuration,没有 addMapper
Configuration config = new Configuration(environment);
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(config);
// 后续 getMapper 会报错:Type interface xxx is not known to the MapperRegistry
// ✅ 正确:必须在 build 前注册
Configuration config = new Configuration(environment);
config.addMapper(EmployeeMapper.class);  // 关键步骤!
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(config);

2. XML 与注解混用时路径不对

// Java 代码方式中 addMapper 会自动查找同名 XML,但 XML 必须
// 与 Mapper 接口在同一 classpath 目录下,且文件名完全一致。
// 例如:org/feixiang/mapper/EmployeeMapper.java
//       对应 org/feixiang/mapper/EmployeeMapper.xml

3. 生产环境用 Java 代码硬编码密码

// ❌ 危险:密码写在代码中,提交到 Git 就泄露了
DataSource ds = new PooledDataSource(..., "root", "MyPassword123");

大翔的忠告:生产环境务必使用 XML + properties 外置敏感信息。

面试考点

  1. MyBatis 有几种构建 SqlSessionFactory 的方式?分别是什么?

    • 两种:基于 XML 配置文件(build(InputStream))和基于 Java Configuration 对象(build(Configuration))。
  2. configuration.addMapper(Class) 背后做了什么?

    • 将 Mapper 接口注册到 MapperRegistry,同时自动查找 classpath 下同名的 XML 映射文件并加载。
  3. 什么场景下应该用 Java 代码方式而非 XML?

    • 单元测试(内存数据库、无需外部文件)、快速原型验证、需要动态构建配置的场景。
  4. Java 代码方式能否完全替代 XML 映射文件?

    • 不能。复杂映射(嵌套联合映射、动态 SQL)仍需要 XML 映射文件。Java 注解有表达能力上限。
上一页
SqlSession核心方法
下一页
Mapper接口与映射方式