1. 课程导入与工程环境搭建
企业级 Java 应用的数据访问层,长期面临两个核心诉求:一是把数据库操作从业务代码中解耦出来,二是让事务、连接、异常这些横切关注点得到统一治理。Spring 与 MyBatis 的组合正是围绕这两点形成的成熟方案。理解它们各自的角色定位,是搭建工程环境之前必须先建立的心智模型。
一、Spring 与 MyBatis 的角色分工
MyBatis 是一款半自动的持久层框架,它把 SQL 的控制权交还给开发者,同时负责参数映射、结果集映射、JDBC 资源释放等重复劳动。它的核心对象是 SqlSessionFactory、SqlSession 与 Mapper 接口,其中 Mapper 接口通过动态代理把方法调用翻译成具体的 SQL 执行。
Spring 则承担容器与基础设施的角色。它通过 IoC 容器管理 DataSource、SqlSessionFactory、Mapper 代理对象等 Bean 的生命周期;通过 DataSourceTransactionManager 提供声明式事务;通过 AOP 把事务、日志等横切逻辑织入 Service 方法。换句话说,MyBatis 解决“SQL 怎么写、结果怎么映射”,Spring 解决“对象谁来管、事务谁来控、资源谁来释放”。
两者结合后,业务代码只需注入 Mapper 接口并调用方法,事务边界由 @Transactional 声明,连接由连接池统一分配。这种分工使得数据访问层既保留了 SQL 的可控性,又获得了企业级的事务与资源管理能力。
二、Maven 多模块工程结构
企业项目通常不会把所有代码堆在一个模块里。推荐按职责拆分为父工程加若干子模块,父工程只做依赖版本与插件管理,子模块各自承担明确职责。一个典型结构如下:
enterprise-data-access/
├── pom.xml (父工程:dependencyManagement 统一版本)
├── eda-common/ (通用工具、统一响应、异常定义)
│ └── pom.xml
├── eda-dao/ (实体、Mapper 接口、XML 映射文件)
│ └── pom.xml
├── eda-service/ (业务逻辑、事务声明)
│ └── pom.xml
└── eda-web/ (Controller、启动类、配置文件)
└── pom.xml
父工程的 packaging 必须是 pom,并在 dependencyManagement 中锁定 Spring Boot、MyBatis Starter、MySQL 驱动等版本。子模块通过 <parent> 继承父工程,引用依赖时无需再写版本号,从而避免多模块间版本漂移。模块依赖方向应保持单向:web 依赖 service,service 依赖 dao,dao 依赖 common,禁止反向依赖。
三、依赖版本管理与 Spring Boot 整合起步依赖
Spring Boot 通过 spring-boot-dependencies 这个 BOM 统一管理了大量常用依赖的版本。整合 MyBatis 时,官方推荐使用 mybatis-spring-boot-starter,它内部已经传递引入了 mybatis、mybatis-spring 以及 spring-boot-starter-jdbc。父工程中应这样声明:
<properties>
<spring-boot.version>3.2.5</spring-boot.version>
<mybatis-spring-boot.version>3.0.3</mybatis-spring-boot.version>
<mysql.version>8.0.33</mysql.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
这里有一个容易踩的坑:mybatis-spring-boot-starter 的版本必须与 Spring Boot 大版本匹配。Spring Boot 3.x 要求 MyBatis Starter 3.x,因为 Spring Boot 3 基于 Jakarta EE 9+,包名已从 javax.* 迁移到 jakarta.*。若在 Spring Boot 3 项目中误用 2.x 的 Starter,启动时会因找不到 javax.sql.DataSource 相关类而失败。
四、自动配置与最小可运行验证
引入 Starter 后,Spring Boot 的自动配置会读取 application.yml 中的数据源信息,自动创建 DataSource、SqlSessionFactory 和 SqlSessionTemplate。开发者只需在启动类上添加 @MapperScan 指定 Mapper 接口所在包,或在每个 Mapper 接口上标注 @Mapper。
spring:
datasource:
url: jdbc:mysql://localhost:3306/eda_demo?useSSL=false&serverTimezone=Asia/Shanghai
username: eda_user
password: eda_pass_2024
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
minimum-idle: 2
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.eda.dao.entity
configuration:
map-underscore-to-camel-case: true
验证环境是否搭建成功,最直接的方式是写一个最小测试:在 eda-dao 中定义一个 UserMapper 接口,声明 User selectById(Long id),在 XML 中编写对应查询,然后在测试类中注入该 Mapper 并调用。若返回对象字段与数据库列正确映射,说明数据源、SqlSessionFactory、Mapper 代理、结果映射四条链路全部打通。若启动报 Failed to configure a DataSource,通常是 application.yml 未被加载或 URL 拼写错误;若报 Invalid bound statement,则多半是 mapper-locations 路径不匹配或 XML 的 namespace 与接口全限定名不一致。
maven-compiler-plugin 的 source 与 target 为 17(与 Spring Boot 3 要求一致),并开启 -parameters 编译参数,否则 MyBatis 在按参数名映射时可能抛出 Parameter 'xxx' not found。