目录
[一、MyBatis Generator插件的安装](#一、MyBatis Generator插件的安装)
[五、MyBatis Generator工作原理](#五、MyBatis Generator工作原理)
我们在web开发初期,有很多工作需要做。其中,数据库建表后,生成实体类,mapper接口和SQL语句均需要完成。有没有一个工具,可以帮我们完成上述工作:生成实体类,生成简单的mapper接口,生成配套的简单的通用的结构化查询SQL。
事实上,是有的。就是我们本节将要使用的MyBatis Generator插件。
一、MyBatis Generator插件的安装
在pom文件中,引入generator插件。
XML
<!-- MyBatis Generator Maven插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
<includeCompileDependencies>true</includeCompileDependencies>
</configuration>
<dependencies>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
</plugin>
这里我们指定了一个待读取的配置文件src/main/resources/generatorConfig.xml,这个文件中有我们希望读取的数据库和表,以及一些配置信息。
最关键的是,插件运行在独立的ClassLoader,不会继承pom文件中的mysql驱动。但是我们的MBG(MyBatis Generator)需要数据库驱动,所以需要单独添加,选择8.0.33版本的兼容性会更好。
刷新Maven后可以看见插件。

这个插件不需要提前导入mybatis依赖,因为其自身已经实现mybatis的相关功能。
二、编写配置类
我们先建立如下数据库和表:
sql
-- 1. 创建数据库
CREATE DATABASE IF NOT EXISTS `demo_db`
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE `demo_db`;
-- 2. 用户表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
`username` VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`email` VARCHAR(100) COMMENT '邮箱',
`phone` VARCHAR(20) COMMENT '手机号',
`status` TINYINT DEFAULT 1 COMMENT '状态:0禁用 1启用',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 3. 商品表
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
`id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '商品ID',
`product_name` VARCHAR(200) NOT NULL COMMENT '商品名称',
`price` DECIMAL(10,2) NOT NULL COMMENT '单价',
`stock` INT DEFAULT 0 COMMENT '库存数量',
`category` VARCHAR(50) COMMENT '分类',
`description` TEXT COMMENT '商品描述',
`status` TINYINT DEFAULT 1 COMMENT '状态:0下架 1上架',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';
-- 4. 订单表(关联用户和商品)
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
`id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '订单ID',
`order_no` VARCHAR(32) NOT NULL UNIQUE COMMENT '订单编号',
`user_id` INT NOT NULL COMMENT '用户ID',
`product_id` INT NOT NULL COMMENT '商品ID',
`quantity` INT NOT NULL COMMENT '购买数量',
`total_price` DECIMAL(10,2) NOT NULL COMMENT '总价',
`order_status` TINYINT DEFAULT 0 COMMENT '订单状态:0待支付 1已支付 2已发货 3已完成 4已取消',
`pay_time` DATETIME COMMENT '支付时间',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`),
FOREIGN KEY (`product_id`) REFERENCES `product`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
demo_db库中有三张表:用户表,商品表和订单表。
我们希望插件也能创建出三个对应的实体类,User、Product、Order
并且我们希望:实体类中的属性应该符合小驼峰命名规则,实体类的属性中应该有comment注释,还有就是实体类中属性的类型应该是这样的:int->Integer,bigint->Long,vahchar()->String,tinyint->Byte,DateTime->LocalDateTime这样做是应为Date.toString()会根据时区显示同样的数据不同地区显示不同,使用LocalDateTime后toString()就是一个不依赖时区的输出,Decaimal(10,2)-> BigDecimal一共十位数字,小数点后保留两位。
MBG默认会自动完成小驼峰命名规则的转换。
现在需要处理注释,MBG默认的注释可以选择部分开启,但是仍然会重复生成很多没用的注释。所以我们希望创建一个配置类来描述注释的形式。
使用配置类时,需要先导入mybatis-generator依赖。
XML
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version> <!-- 与你的插件版本保持一致 -->
</dependency>
创建CustomCommentGenerator配置类
java
package com.miao.mbg.config;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.internal.DefaultCommentGenerator;
public class CustomCommentGenerator extends DefaultCommentGenerator {
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
String remarks = introspectedColumn.getRemarks();
if (remarks != null && !remarks.isEmpty()) {
field.addJavaDocLine("/**");
field.addJavaDocLine(" * " + remarks);
field.addJavaDocLine(" */");
}
}
@Override
public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
String remarks = introspectedTable.getRemarks();
if (remarks != null && !remarks.isEmpty()) {
topLevelClass.addJavaDocLine("/**");
topLevelClass.addJavaDocLine(" * " + remarks);
topLevelClass.addJavaDocLine(" */");
}
}
@Override
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
String remarks = introspectedTable.getRemarks();
if (remarks != null && !remarks.isEmpty()) {
innerClass.addJavaDocLine("/**");
innerClass.addJavaDocLine(" * " + remarks);
innerClass.addJavaDocLine(" */");
}
}
@Override
public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
}
@Override
public void addGetterComment(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
}
@Override
public void addSetterComment(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
}
}
而且我们不希望生成set和get方法,我们用@Data注解更加简洁。
所以我们需要在此建立一个配置类,关闭set和get方法的生成。
java
package com.miao.mbg.config;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import java.util.List;
/**
* 自定义 MBG 插件:不生成 getter/setter,改用 Lombok 注解
*/
public class LombokPlugin extends PluginAdapter {
@Override
public boolean validate(List<String> warnings) {
return true;
}
@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable) {
topLevelClass.addAnnotation("@Data");
topLevelClass.addAnnotation("@NoArgsConstructor");
topLevelClass.addAnnotation("@AllArgsConstructor");
topLevelClass.addImportedType(new FullyQualifiedJavaType("lombok.Data"));
topLevelClass.addImportedType(new FullyQualifiedJavaType("lombok.NoArgsConstructor"));
topLevelClass.addImportedType(new FullyQualifiedJavaType("lombok.AllArgsConstructor"));
return true;
}
@Override
public boolean modelGetterMethodGenerated(Method method,
TopLevelClass topLevelClass,
IntrospectedColumn introspectedColumn,
IntrospectedTable introspectedTable,
ModelClassType modelClassType) {
return false;
}
@Override
public boolean modelSetterMethodGenerated(Method method,
TopLevelClass topLevelClass,
IntrospectedColumn introspectedColumn,
IntrospectedTable introspectedTable,
ModelClassType modelClassType) {
return false;
}
}
我们既然用到了Lombok就需要引入依赖。
XML
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
顺便把mybatis也引入了,未来肯定会用到。
三、generatorConfig.xml配置文件
在src/main/resource下创建配置文件
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>
<!-- ============================================================ -->
<!-- 上下文配置 -->
<!-- targetRuntime: 使用 MyBatis3 标准模式 -->
<!-- defaultModelType: flat 表示每个表生成一个实体类 -->
<!-- ============================================================ -->
<context id="MysqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
<!-- ========================================================== -->
<!-- 通用属性配置 -->
<!-- ========================================================== -->
<!-- 禁止XML增量合并,防止重复生成BaseResultMap -->
<property name="mergeable" value="false"/>
<!-- 关键字自动加反引号,避免与MySQL保留字冲突 -->
<property name="autoDelimitKeywords" value="true"/>
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!-- ========================================================== -->
<!-- 插件配置 -->
<!-- 使用自定义Lombok插件:自动添加@Data,禁用getter/setter生成 -->
<!-- ========================================================== -->
<plugin type="com.miao.mbg.config.LombokPlugin"/>
<!-- ========================================================== -->
<!-- 注释生成器配置 -->
<!-- 使用自定义注释生成器:读取数据库COMMENT生成JavaDoc注释 -->
<!-- ========================================================== -->
<commentGenerator type="com.miao.mbg.config.CustomCommentGenerator">
<!-- 不抑制所有注释 -->
<property name="suppressAllComments" value="false"/>
<!-- 抑制生成时间戳(减少Git提交噪音) -->
<property name="suppressDate" value="true"/>
<!-- 添加数据库字段注释 -->
<property name="addRemarkComments" value="true"/>
<!-- 使用新版注释解析方式(MySQL 8.0+) -->
<property name="useLegacyRemark" value="false"/>
</commentGenerator>
<!-- ========================================================== -->
<!-- JDBC数据库连接配置 -->
<!-- nullCatalogMeansCurrent=true: 只查询当前数据库,避免跨库 -->
<!-- ========================================================== -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/demo_db?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&useUnicode=true&useSSL=false&nullCatalogMeansCurrent=true"
userId="root"
password="182204">
</jdbcConnection>
<!-- ========================================================== -->
<!-- 类型解析器 -->
<!-- useJSR310Types: DATETIME → LocalDateTime -->
<!-- forceBigDecimals: DECIMAL → BigDecimal -->
<!-- ========================================================== -->
<javaTypeResolver>
<property name="useJSR310Types" value="true"/>
<property name="forceBigDecimals" value="true"/>
</javaTypeResolver>
<!-- ========================================================== -->
<!-- 实体类生成配置 -->
<!-- targetPackage: 实体类包名 -->
<!-- targetProject: 生成路径 -->
<!-- ========================================================== -->
<javaModelGenerator targetPackage="com.miao.mbg.entity"
targetProject="src/main/java">
<!-- 不启用子包 -->
<property name="enableSubPackages" value="false"/>
<!-- 去除字符串前后空格 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- ========================================================== -->
<!-- Mapper XML生成配置 -->
<!-- ========================================================== -->
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- ========================================================== -->
<!-- Mapper接口生成配置 -->
<!-- type=XMLMAPPER: 生成基于XML的Mapper接口 -->
<!-- ========================================================== -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.miao.mbg.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!-- ========================================================== -->
<!-- 表配置 -->
<!-- enableXxxByExample=false: 不生成Example类 -->
<!-- generatedKey: 主键自增策略 -->
<!-- columnOverride: 自定义字段类型映射 -->
<!-- ========================================================== -->
<!-- 1. 用户表 -->
<table tableName="user" domainObjectName="User"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false">
<generatedKey column="id" sqlStatement="MYSQL"/>
</table>
<!-- 2. 商品表 -->
<table tableName="product" domainObjectName="Product"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false">
<generatedKey column="id" sqlStatement="MYSQL"/>
</table>
<!-- 3. 订单表 -->
<!-- order 是 MySQL 保留字,autoDelimitKeywords=true 会自动加反引号 -->
<table tableName="order" domainObjectName="Order"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false">
<generatedKey column="id" sqlStatement="MYSQL"/>
</table>
</context>
</generatorConfiguration>
四、编写代码生成方法
在启动类同级目录下创建GeneratorMain类
java
package com.miao.mbg;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class GeneratorMain {
public static void main(String[] args) throws Exception {
System.setProperty("file.encoding", "UTF-8");
List<String> warnings = new ArrayList<>();
File configFile = new File("src/main/resources/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(true);
MyBatisGenerator generator = new MyBatisGenerator(config, callback, warnings);
generator.generate(null);
warnings.forEach(System.out::println);
System.out.println("代码生成完成!");
}
}
我们运行后,就能看到想要的实体和mapper啦。

使用前,一定要把com.包目录改成你自己的,否则会出问题。
五、MyBatis Generator工作原理
MBG会读取我们的xml配置,然后连接数据库,然后读取元数据。并不是读取表结构。
元数据存放在哪里呢?
在information_schema中:


像TABLES、COLUMNS这些都是元数据,我们可以看看COLUMNS的表结构,看看里面存了什么。

里面存库名,表名,和字段名以及一些数据类型,和约束。

是所有的库+表+对应字段,数据非常多。

也就是你定义过的字段,这里面都会出现。
那么MBG实际的工作就是:
sql
-- MBG 实际做的事(通过 JDBC DatabaseMetaData)
SELECT
TABLE_NAME,
TABLE_COMMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'demo_db';
SELECT
COLUMN_NAME,
DATA_TYPE,
CHARACTER_MAXIMUM_LENGTH,
IS_NULLABLE,
COLUMN_DEFAULT,
COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'demo_db'
AND TABLE_NAME = 'user';
首先拿到需要处理的表名,和表注释。
然后分别去拿表中的列和数据类型以及字段上的注释和约束。
然后MBG拿着这些数据去创建实体。
那么保证读取到目标库的目标表就成了关键,怎么做到的?
首先是URL配合连接参数。
XML
connectionURL="jdbc:mysql://localhost:3306/demo_db?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&useUnicode=true&useSSL=false&nullCatalogMeansCurrent=true"
首先指定了数据库连接,但是还有一个关键参数nullCatalogMeansCurrent=true,它决定了我们不去读取其他库中的相同名称的表。不然会造成字段混乱,生成的实体类可能字段会增加或者减少。
其次就是元数据查询过滤,这个是MBG做的工作,我们知道即可。
最后是xml里的配置和我们配置类里的配置,我们指定了想要生成的表,具体配置还需要仔细研读我们的xml配置文件。
最后提出一个问题:Maven插件运行在独立的类加载器中,所以我们引入了Lombok和mysql驱动,那么我们的配置类默认是不会被读取的。所以此时如果你使用终端或者Maven面板去运行MBG插件,配置类是会读取失败的。
所以我们选择使用一个Main方法,依靠项目类加载器那么肯定就可以读取到配置类了。这也是最为保险的手段,其次就是文件编码格式,为了避免编码错乱,统一使用UTF-8编码即可。
六、总结
本节我们学会了使用Mybatis Generator来帮助我们快速生成实体类、Mapper、和对应的结构化SQL。包括如何自定义配置类,以及为了读取配置类我们采取使用项目类加载器来生成代码的方法。了解了MBG是去读取Mysql的元数据信息来构建实体类的。
以上就是所有内容,如果有任何问题请指出,作者会认真勘误。