在使用 MyBatis 进行项目开发时,MyBatis Generator(MBG)是一个非常实用的工具,它能够根据数据库表结构自动生成实体类、Mapper 接口以及 XML 映射文件,大大提高了开发效率。本文将详细介绍如何配置 MyBatis Generator 以生成接口和 XML 映射文件,并对不同的
targetRuntime
风格进行介绍和推荐。
一、环境准备
在开始之前,确保你的项目中已经添加了 MyBatis Generator 的相关依赖。如果你使用的是 Maven 项目,可以在 pom.xml
文件中添加如下依赖:
<dependencies>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- MyBatis Generator 插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
二、配置文件详解
在 src/main/resources
目录下创建 generatorConfig.xml
配置文件,以下是详细的配置内容及注释:
<?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>
<!-- 配置上下文,id 唯一标识,targetRuntime 指定生成代码的方式,风格 MyBatis3DynamicSql,MyBatis3,MyBatis3Simple,MyBatis3Kotlin -->
<context id="mysqlTables" targetRuntime="MyBatis3" defaultModelType="flat">
<!-- 自动检查关键字,为关键字增加反引号,如:`type` -->
<property name="autoDelimitKeywords" value="true"/>
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!-- 指定生成的 Java 文件编码 -->
<property name="javaFileEncoding" value="UTF-8"/>
<!-- 对生成的注释进行控制 -->
<commentGenerator>
<!-- 由于此插件生成的注释不太美观,这里设置不生成任何注释 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!-- 数据库链接 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/your_database"
userId="your_username"
password="your_password">
<!-- 解决多个重名的表生成表结构不一致问题 -->
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<!-- 不强制将所有的数值类型映射为 Java 的 BigDecimal 类型 -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 配置生成实体类的位置和包名 -->
<javaModelGenerator targetPackage="com.example.model" targetProject="src/main/java"/>
<!-- 配置生成 XML 映射文件的位置和包名 -->
<sqlMapGenerator targetPackage="com.example.mapper" targetProject="src/main/resources"/>
<!-- 配置生成 Mapper 接口的位置和包名,type="XMLMAPPER" 表示生成 XML 映射文件 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.example.mapper" targetProject="src/main/java"/>
<!-- 配置要生成代码的表,tableName 指定数据库中的表名,domainObjectName 指定生成的实体类名 -->
<!-- 要生成对应表配置,若想要生成全部表 使用 tableName="%" 即可 -->
<!-- 订单详情表 -->
<table tableName="order_detail" domainObjectName="OrderDetail"
<!-- 不生成Example -->
enableCountByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
enableUpdateByExample="false">
<!-- 自增主键列 -->
<generatedKey column="id" sqlStatement="MYSQL" identity="true"/>
<!-- 根据实际需求添加其他列的映射配置 -->
</table>
</context>
</generatorConfiguration>
三、生成代码
在项目根目录下打开终端,运行以下命令生成代码:
mvn mybatis-generator:generate
或者点击 mybatis-generator 组件
运行命令后,MyBatis Generator 会根据
generatorConfig.xml
配置文件生成 Mapper 接口和对应的 XML 映射文件。
四、不同 targetRuntime
风格介绍和推荐
1. MyBatis3
-
描述:生成兼容 MyBatis 3.x 的代码。这是最常用的目标,支持 MyBatis 的基础功能,生成 Example 类、SQL 语句和常规的 Mapper 接口。
-
使用场景:当使用 MyBatis 3.x 时,这是最常见的选择。
-
推荐:如果你的项目需要使用 MyBatis 3.x 的所有功能,包括复杂的查询和条件类,选择
MyBatis3
风格是一个不错的选择。
2. MyBatis3Simple
-
描述:生成更加简化的代码,省略了 Example 类和其他复杂功能。
-
使用场景:当项目不需要复杂查询或额外的功能时,可以选择该选项,以减少生成的代码量。
-
推荐:如果你的项目只需要基本的 CRUD 操作,不需要复杂的查询条件,选择
MyBatis3Simple
风格可以减少生成的代码量,使项目更加简洁。
3. MyBatis3DynamicSql
-
描述:生成使用 MyBatis3 风格的动态 SQL 的代码。该选项支持通过 MyBatis 提供的动态 SQL 功能(如 Example 类、Criteria 和动态 SQL 构建器)生成更加灵活和复杂的 SQL 查询。
-
使用场景:如果你需要动态生成复杂的 SQL 语句,并使用 MyBatis 3.x 的动态 SQL 构建功能,选择该选项。
-
推荐:官方推荐使用
MyBatis3DynamicSql
风格,因为它提供了更高的灵活性和更强大的动态 SQL 支持,使用 Lambda 表达式可以避免条件对象渗透到上一层,代码更加简洁和易于维护。
4. MyBatis3Kotlin
-
描述:生成 Kotlin 代码。
-
使用场景:如果你的项目使用 Kotlin 语言,可以选择该选项。
-
推荐:如果你的项目是基于 Kotlin 开发的,选择
MyBatis3Kotlin
风格可以生成与 Kotlin 语言兼容的代码,利用 Kotlin 的语言特性,使代码更加简洁和高效。
五、生成的 Example 类及解决办法
1. 生成的 Example 类
当使用 MyBatis3
风格时,MyBatis Generator 会生成 Example 类,这些类用于构建复杂的查询条件。例如,生成的 UserExample
类可能如下所示:
package com.example.model;
import java.util.ArrayList;
import java.util.List;
public class UserExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public UserExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(Integer value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
// 其他条件方法...
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}
2. 问题及解决办法
问题 1:Example 类过于复杂,导致代码冗余
解决办法:
-
使用
MyBatis3Simple
风格:如果你的项目不需要复杂的查询条件,可以选择MyBatis3Simple
风格,这样可以避免生成 Example 类,减少代码冗余。 -
自定义生成策略:如果你仍然需要使用
MyBatis3
风格,但希望减少 Example 类的复杂性,可以通过自定义生成策略来简化 Example 类。例如,可以修改generatorConfig.xml
文件中的<commentGenerator>
配置,减少生成的注释和不必要的代码。
问题 2:Example 类的使用导致代码可读性差
解决办法:
-
使用 Lambda 表达式:在
MyBatis3DynamicSql
风格中,可以使用 Lambda 表达式来构建查询条件,使代码更加简洁和易于理解。例如:
List<User> users = userMapper.selectMany(SelectStatementProvider.builder()
.select(UserDynamicSqlSupport.id, UserDynamicSqlSupport.name, UserDynamicSqlSupport.email)
.from(UserDynamicSqlSupport.user)
.where(UserDynamicSqlSupport.name, isEqualTo("张三"))
.build());
-
封装查询条件:可以封装查询条件的构建逻辑,使代码更加模块化和易于维护。例如,可以创建一个查询条件构建器类,将复杂的查询条件封装起来:
public class UserQuery {
private UserExample example;
public UserQuery() {
this.example = new UserExample();
}
public UserQuery idIsNull() {
example.createCriteria().andIdIsNull();
return this;
}
public UserQuery idIsNotNull() {
example.createCriteria().andIdIsNotNull();
return this;
}
public UserQuery idEqualTo(Integer id) {
example.createCriteria().andIdEqualTo(id);
return this;
}
// 其他条件方法...
public UserExample build() {
return example;
}
}
// 使用封装的查询条件构建器
List<User> users = userMapper.selectByExample(new UserQuery().idEqualTo(1).build());
六、总结
通过以上步骤,我们成功配置了 MyBatis Generator 以生成接口和 XML 映射文件。在实际开发中,合理使用 MyBatis Generator 可以显著提高开发效率,减少手动编写重复代码的工作量。不同的 targetRuntime
风格各有优缺点,根据项目的具体需求选择合适的风格可以更好地满足开发需求。
生成的 Example 类虽然功能强大,但也可能导致代码冗余和可读性差。通过选择合适的风格或自定义生成策略,可以有效解决这些问题,使代码更加简洁和易于维护。