第 5 章 [生产力] MyBatis 生态工具
摘要: 优秀的框架往往拥有一个繁荣的生态。MyBatis 也不例外,社区为其贡献了许多强大的工具来自动化常见的开发任务。本章我们将聚焦于两个最核心的生产力工具:首先,我们将学习如何使用 PageHelper 插件,用两行代码优雅地实现曾一度令人头疼的物理分页功能;接着,我们将掌握 MyBatis Generator 逆向工程,实现根据数据库表一键自动生成 POJO、Mapper 接口和 XML 文件,彻底告别重复的手动编码。
5.1. [分页] PageHelper - 优雅的分页助手
分页是 Web 开发中最常见的需求之一。如果没有工具,我们需要手动实现非常繁琐的逻辑。
5.1.1. 背景:手动分页的痛点
- SQL 耦合: 我们需要在 SQL 语句中硬编码
LIMIT ?, ?,这意味着 Mapper 接口的每个分页方法都需要额外接收 startIndex 和 pageSize 两个参数。 - 功能割裂: 为了在页面上显示“共 X 页,共 Y 条”等信息,我们通常需要执行一条额外的
SELECT COUNT(*) 查询来获取总记录数。这两步操作在业务逻辑中是分开的,管理起来很麻烦。
PageHelper 的出现,完美地解决了这些问题。它以非侵入的方式,让我们对分页的处理变得极其简单。
5.1.2. PageHelper 快速上手
集成 PageHelper 只需两步。
1. 添加 Maven 依赖
首先,我们在 pom.xml 文件中添加 PageHelper 的依赖。
文件路径: pom.xml
1 2 3 4 5
| <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.3.3</version> </dependency>
|
2. 配置 MyBatis 插件
PageHelper 的工作原理是作为 MyBatis 的一个 拦截器 (Interceptor),它会拦截我们即将执行的 SQL 语句,并自动地在末尾追加上物理分页的关键字(如 LIMIT)。我们需要在全局配置文件中注册这个拦截器。
文件路径: src/main/resources/mybatis-config.xml
危险: 根据 MyBatis DTD 规范,正确的顺序应该是如下的代码块,一定要严格按照,非常严格,否则很容易导致报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <?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> <settings> <setting name="lazyLoadingEnabled" value="true"/> </settings>
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"/> </plugins>
<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/bank_db"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments>
<mappers> <mapper resource="mappers/AccountMapper.xml"/> <mapper resource="mappers/CarMapper.xml"/> <mapper resource="mappers/CustomerMapper.xml"/> </mappers> </configuration>
|
5.1.3. 实践与演示
PageHelper 最具魅力的一点是:我们无需修改任何已有的 Mapper 接口和 SQL 语句。我们可以对任何一个返回 List 的查询方法进行分页。
1. 准备一个查询全部的方法
我们在 CarMapper 中准备一个查询所有汽车信息的方法。
文件路径 (接口): src/main/java/com/example/bank/mapper/CarMapper.java (添加方法)
文件路径 (XML): src/main/resources/mappers/CarMapper.xml (添加)
1 2 3
| <select id="selectAll" resultType="com.example.bank.pojo.Car"> select id, car_num, brand, guide_price, produce_time, car_type from t_car </select>
|
2. 编写测试
现在,我们来见证 PageHelper 的神奇之处。
核心用法:
- 在执行查询 之前,调用
PageHelper.startPage(pageNum, pageSize) 来“声明”接下来的一次查询需要分页。 - 正常执行你的查询方法。
- 用
new PageInfo<>(查询结果) 来包装 List,从中获取详尽的分页信息。
文件路径: src/test/java/com/example/bank/test/PageHelperTest.java (新建)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package com.example.bank.test;
import com.example.bank.mapper.CarMapper; import com.example.bank.pojo.Car; import com.example.bank.utils.SqlSessionUtil; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSession; import org.junit.jupiter.api.Test; import java.util.List;
@Slf4j public class PageHelperTest {
@Test void testPageHelper() { try (SqlSession sqlSession = SqlSessionUtil.openSession()) { CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
int pageNum = 1; int pageSize = 2; PageHelper.startPage(pageNum, pageSize);
List<Car> cars = carMapper.selectAll();
PageInfo<Car> pageInfo = new PageInfo<>(cars, 5);
log.info("分页信息: {}", pageInfo);
} } }
|
前瞻提示: 在 Spring Boot 项目中集成 PageHelper 更加简单,通常只需引入一个 pagehelper-spring-boot-starter 依赖,连 XML 中的插件配置都可以省略,真正做到开箱即用。
5.2. [提效] MyBatis Generator - 告别重复劳动 (终极讲解重构版)
对于一个拥有几十甚至上百张表的项目,手动为每张表创建 POJO、Mapper 接口和 XML 文件,是一项极其枯燥、耗时且容易出错的工作。MyBatis Generator (MBG) 就是为了解决这个问题而生的自动化工具。
5.2.1. Generator 配置详解
配置 MBG 分为两步:在 pom.xml 中引入插件,并编写一个 generatorConfig.xml 配置文件。
1. 配置 Maven 插件
首先,我们需要在项目的 pom.xml 中引入 mybatis-generator-maven-plugin 插件,并为其提供数据库驱动。
文件路径: pom.xml (在 <build> 标签内添加)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <build> <plugins> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.4.2</version> <dependencies> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.2.0</version> </dependency> </dependencies> <configuration> <configurationFile>src/main/resources/generatorConfig.xml</configurationFile> <overwrite>true</overwrite> </configuration> </plugin> </plugins> </build>
|
2. 详解 generatorConfig.xml
这个文件是 MBG 的“行动指南”,也是我们自定义生成规则的核心。下面,我们将逐一拆解它的关键配置项。
文件路径: src/main/resources/generatorConfig.xml (新建)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="MySqlContext" targetRuntime="MyBatis3">
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/bank_db" userId="root" password="root"/>
<javaModelGenerator targetPackage="com.example.bank.pojo.gen" targetProject="src/main/java"/>
<sqlMapGenerator targetPackage="com.example.bank.mapper.gen" targetProject="src/main/resources"/>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.example.bank.mapper.gen" targetProject="src/main/java"/>
<table tableName="t_account" domainObjectName="AccountGen"/> <table tableName="t_customer" domainObjectName="CustomerGen"/>
</context> </generatorConfiguration>
|
请注意,targetProject 和 targetPackage 会组合在一起决定最终的输出路径。例如 targetProject="src/main/java" 和 targetPackage="com.example.bank.pojo.gen" 会将文件生成在 src/main/java/com/example/bank/pojo/gen/ 目录下。
5.2.2. 执行生成与验证
1. 执行生成
在 IDEA 的 Maven 面板中,找到 mybatis-generator 插件,并双击 generate 目标来执行。
执行成功后,您的项目目录中会自动生成如下文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| src ├── main │ ├── java │ │ └── com │ │ └── example │ │ └── bank │ │ ├── mapper │ │ │ └── gen │ │ │ ├── AccountGenMapper.java │ │ │ └── CustomerGenMapper.java │ │ └── pojo │ │ └── gen │ │ ├── AccountGen.java │ │ ├── AccountGenExample.java │ │ ├── CustomerGen.java │ │ └── CustomerGenExample.java │ └── resources │ └── com │ └── example │ └── bank │ └── mapper │ └── gen │ ├── AccountGenMapper.xml │ └── CustomerGenMapper.xml
|
2. 验证生成的代码
MBG 生成的代码非常强大,它不仅包含了基础的 CRUD,还有一个 Example 类,可以让我们以面向对象的方式构建复杂的 WHERE 子句(这种方式被称为 QBC - Query By Criteria)。
文件路径: src/test/java/com/example/bank/test/GeneratorTest.java (新建)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package com.example.bank.test;
import com.example.bank.mapper.gen.AccountGenMapper; import com.example.bank.pojo.gen.AccountGen; import com.example.bank.pojo.gen.AccountGenExample; import com.example.bank.utils.SqlSessionUtil; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSession; import org.junit.jupiter.api.Test; import java.util.List; import static org.assertj.core.api.Assertions.assertThat;
@Slf4j public class GeneratorTest { @Test void testGeneratorCode() { try (SqlSession sqlSession = SqlSessionUtil.openSession()) { AccountGenMapper mapper = sqlSession.getMapper(AccountGenMapper.class);
AccountGenExample example = new AccountGenExample(); example.createCriteria().andBalanceGreaterThan(20000.00);
List<AccountGen> accounts = mapper.selectByExample(example);
assertThat(accounts).hasSize(1); assertThat(accounts.get(0).getActno()).isEqualTo("act-001"); log.info("MBG 生成的代码查询成功: {}", accounts); } } }
|
可以看到,通过详细配置,MBG 成为了我们手中的一把利器。它为我们生成了功能完备、类型安全的数据访问层代码,使我们能从重复的劳动中解放出来,更专注于业务逻辑的实现。