ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

MyBatis Generator 2021最新版配置详解与实战避坑指南

MyBatis Generator 2021最新版配置详解与实战避坑指南 今年把项目里用了几年的 MyBatis Generator 重新梳理了一遍发现网上很多教程还停留在 Eclipse 插件时代或者直接照搬老版本配置。实际上 3.5.x 之后这个工具在 Maven 插件、类型转换、自定义注释上的玩法已经变了不少。这篇不是那种从零开始一行行念文档的入门贴我尽量把“文档里不会写但实操一定会遇到”的东西讲清楚比如怎么避免覆盖手写代码、时间类型映射怎么调、多个数据源怎么配、生成完怎么验证。适合刚接触 MyBatis Generator 的新人也适合已经用了很久但一直踩着默认配置的老手。1. 为什么还要用 mybatis-generator以及它能干掉哪些重复劳动1.1 核心需求解析实体、Mapper、Example 文件到底生成了些什么先说结论MyBatis Generator 的职责非常单一——读取数据库表结构生成对应的 Java Bean、Mapper 接口、Mapper XML以及对单表做 CRUD 的通用方法。它不负责业务逻辑更不是 ORM 框架只是一个把“建表之后写基础代码”这个重复动作自动化的生成器。以一张常见的 user 表为例包含 id、username、password、email、create_time、update_time 这 6 个字段运行生成器后会自动产生 5 个文件生成文件作用说明User.java对应表的实体类每个字段一个属性包含 getter/setterUserExample.java查询条件构造器用来拼 where 条件UserMapper.javaMapper 接口定义了单表操作的抽象方法UserMapper.xmlSQL 映射文件实现接口方法对应的具体 SQLUserDao.java可选旧版本风格的 Dao 接口新版基本不生成可忽略很多第一次用的人会被 UserExample 这个类吓到觉得它特别重。但它其实是 MyBatis Generator 最实用的设计举例来说如果要查“用户名是 admin 并且创建时间在今天之后”的记录传统做法是手写一个select加上动态 SQL 判断而 Example 类允许这样写UserExample example new UserExample(); UserExample.Criteria criteria example.createCriteria(); criteria.andUsernameEqualTo(admin); criteria.andCreateTimeGreaterThan(new Date()); ListUser users userMapper.selectByExample(example);这样的代码可读性很高而且条件拼接完全基于 Java 对象不依赖 XML 里的if判断对于单表复杂查询特别友好。所以熟悉生成器产物的第一件事不是盯着 Mapper.xml 看而是先搞懂 Example 类里那些andXxxEqual、andXxxLike方法是怎么来的——本质上就是表字段名转成驼峰后加上各种查询条件后缀自动生成的。1.2 版本演进与选型思路2021 年到底该用哪个版本标题里写了“2021 最新版”这里我展开解释一下。MyBatis Generator 是 MyBatis 官方提供的子项目当前的主线版本是 3.5.x 系列。3.5.0 版本在 2019 年发布最大变化是支持了基于 Java 8 的 JSR 310 时间类型LocalDate、LocalDateTime解决了一直以来日期类型映射成Date的痛点。后续 3.5.1、3.5.2、3.5.3 陆续修复了一些插件机制和 XML 生成格式的 bug。到了 3.5.6、3.5.7 之后整个工具已经比较稳定配置方式也没再发生过破坏性变更。如果你在 2021 年之后看了这篇笔记我建议直接用当时的最新稳定版比如 3.5.9 或更新的 3.5.x。这类工具没有追求最新版的必要但也不能用太久远的版本否则会遇到两个非常实际的问题高版本 MySQL 驱动Connector/J 8.x和老版本生成器之间偶发时区解析异常。数据库字段类型如果使用了 JSON、ENUM、MEDIUMINT 这类较新的类型老版本可能不认识直接降级成Object。所以我的选择建议是生成器用 3.5.9 左右数据库驱动用 mysql-connector-java 8.0.x 或 8.4.0JDK 用 8 以上即可这套组合在大部分项目里实测下来很稳。2. 使用前的环境准备与核心配置拆解2.1 环境准备清单JDK、数据库驱动、Maven 插件实际操作前需要确认本机环境满足以下条件。这里我用的是 Maven 工程因为这是目前最主流也最方便的项目管理方式强烈建议不要再用 Eclipse 的第三方插件一方面它停止维护很久了另一方面 Maven 插件在 CI/CD 环境里也能直接执行。环境清单如下环境项版本/说明JDK1.8 或以上推荐 8/11/17Maven3.5 或以上数据库MySQL 5.7 或 8.x其他数据库也支持但配置略有差异数据库驱动mysql-connector-java 8.0.x生成器插件mybatis-generator-maven-plugin版本和 core 保持一致接入 Maven 的时候需要在 pom.xml 的 build/plugins 中加入插件。这里有一个容易犯的错误很多人只加了插件却没有在插件的 dependencies 里显式指定数据库驱动。如果你本地的 Maven 仓库没有默认加载 mysql 驱动运行时会直接报 ClassNotFoundException。正确的配置长这样plugin groupIdorg.mybatis.generator/groupId artifactIdmybatis-generator-maven-plugin/artifactId version1.4.2/version configuration configurationFilesrc/main/resources/generatorConfig.xml/configurationFile overwritetrue/overwrite verbosetrue/verbose /configuration dependencies dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency /dependencies /plugin注意overwrite这个参数。设置为 true 时每次运行都会覆盖同名的实体类、Mapper 接口、XML 文件。听起来没什么问题但如果你在生成之后手写过这些文件里的方法再运行一次就会全部丢失连提醒都没有。所以项目规范里一定要规定生成器只负责生成基础 CRUD手写扩展方法必须放到别处或者在生成后整理好再覆盖。2.2 generatorConfig.xml 核心配置逐项说明generatorConfig.xml 是整个工具的核心它决定了生成哪些表、生成到哪个包、是否生成注释、如何映射类型。下面是一份对 MySQL 比较完整的配置我按模块拆开说明。首先是最外层结构?xml version1.0 encodingUTF-8? !DOCTYPE generatorConfiguration PUBLIC -//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd generatorConfiguration !-- 可选的 classPathEntry用于指定驱动 jar 的绝对路径如果 Maven 中已声明则可以不写 -- context idmysqlContext targetRuntimeMyBatis3Simple defaultModelTypeflat ... /context /generatorConfigurationdefaultModelType有几个值我逐一说明。老的文档通常推荐conditional意思是一张表只会生成一个实体类如果表只有一个主键且没有其他字段不会生成单独的 Example 类这个主键查询会合并到实体里面。但实际项目中我们经常要按非主键字段做条件查询所以我更推荐用flat它让每张表固定生成 实体 Example Mapper 三件套逻辑一致不会出现某些表有 Example、某些表没有的混乱局面。在context内部还需要配置注释生成器、JDBC 连接、类型处理器、模型生成器、SQL 映射生成器、客户端生成器、表配置。我挑几个容易踩坑的细说。注释生成器这块默认的注释是author加当前用户名还会带上生成时间导致代码每次生成都不一样对版本控制很不友好。实际情况中团队项目一般会自定义注释把作者写死或者干脆不要注释。如果你不想写 Java 类去自定义可以用一个轻量方案直接注释掉 commentGenerator 配置或者设置commentGenerator property namesuppressAllComments valuetrue/ /commentGenerator但完全关闭注释有个副作用XML 里没有任何说明后续维护时别人看不出这个文件和生成器的关联。我更推荐保留注释但抑制自动生成的作者和时间戳这个需要自定义一个类后面在《进阶手段》章节里我会给完整代码。JDBC 连接配置没什么悬念但有两个隐患值得注意。第一个是useInformationSchemaMySQL 8.x 下建议设置为 true否则生成器读取表注释、字段注释时可能抓到空值。第二个是连接串参数最好显式加上nullCatalogMeansCurrenttrueuseSSLfalseserverTimezoneAsia/Shanghai。前者是为了防止 MySQL 驱动默认返回的 catalog 包含全部库而导致生成器找不到表后者是为了避免时区报错。jdbcConnection driverClasscom.mysql.cj.jdbc.Driver connectionURLjdbc:mysql://localhost:3306/your_db?useUnicodetrueamp;characterEncodingutf8amp;useSSLfalseamp;serverTimezoneAsia/Shanghaiamp;nullCatalogMeansCurrenttrue userIdroot passwordyour_password property namenullCatalogMeansCurrent valuetrue/ /jdbcConnection类型解析器可以配置强制 Java 类型映射比如把数据库的TINYINT(1)映射为Boolean把DECIMAL(10,2)映射为BigDecimal。直接给一份常用配置javaTypeResolver property nameforceBigDecimals valuetrue/ property nameuseJSR310Types valuetrue/ /javaTypeResolverforceBigDecimals设置为 true 后所有小数类型都会映射成 BigDecimal避免精度丢失。useJSR310Types对应 Java 8 时间类型开启后datetime映射为LocalDateTimedate映射为LocalDatetime映射为LocalTime。这里提醒一下如果你的项目还在用 Date 类型或者还在用 MyBatis 3.4.x 而没升级到 3.5.x就必须把useJSR310Types设置为 false否则 MyBatis 对 JSR310 类型的支持不完整会引出类型处理器找不到的报错。接下来是三个生成器的核心配置直接决定代码输出位置javaModelGenerator targetPackagecom.demo.model targetProjectsrc/main/java property nametrimStrings valuetrue/ /javaModelGenerator sqlMapGenerator targetPackagemapper targetProjectsrc/main/resources/ javaClientGenerator typeXMLMAPPER targetPackagecom.demo.mapper targetProjectsrc/main/java/targetProject相对路径的坑非常大。Maven 环境下你可能有src/main/java和src/main/resources两个目录如果不小心把 SQL 映射文件生成到src/main/java下Maven 默认不会把它打包进最终产物运行时会提示 “Invalid bound statement (not found)”。这个坑我至少踩过两次。另外如果项目结构是多 Module 的targetProject 需要写模块的相对路径例如module-common/src/main/java不能直接写src/main/java。table配置是最后一步。默认情况下生成器会扫描连接库中的所有表如果你想精确到某几张表可以用tableName指定table tableNameuser domainObjectNameUser enableInserttrue enableUpdateByPrimaryKeytrue enableDeleteByPrimaryKeytrue enableSelectByPrimaryKeytrue enableCountByExampletrue enableUpdateByExampletrue enableDeleteByExampletrue enableSelectByExampletrue selectByExampleQueryIdtrue/enableXxx系列开关因人而异。如果项目里单表操作非常简单不需要 Example 类的各种 byExample 方法可以全部关闭减少生成代码量。但我个人建议保留selectByExample和countByExample因为分页查询、条件统计这两类需求在业务开发里几乎一定会出现等用到的时候再手写反而费事。3. 三种运行方式与完整实操过程3.1 方式一Maven 插件运行把配置文件写好之后运行命令mvn mybatis-generator:generate这是最常规的方式。如果你在 IDEA 右侧的 Maven 面板里找不到这个插件对应的节点可以先mvn clean一下刷新项目或者在终端里直接执行。运行成功后控制台一般会输出 “BUILD SUCCESS” 并列出生成了哪些文件。我的建议是为了不污染主代码第一次使用可以先把targetProject指向一个临时目录比如src/main/java-tmp生成完之后人工 review 一下实体的字段映射、Mapper 接口的方法命名是否符合项目规范确认没问题再统一移动到正式目录。这个过程虽然多了一步但能发现很多隐藏问题例如某些表没有主键导致生成失败、字段前缀引发的命名不一致。3.2 方式二Java 代码直接调用如果你不想依赖 Maven 插件或者需要把生成动作集成到自己的管理平台里可以直接写 Java 代码调用。适合那种“数据库表结构一变动系统自动重新生成基础代码”的场景。我一般这样写public class GeneratorLauncher { public static void main(String[] args) throws Exception { ListString warnings new ArrayList(); boolean overwrite true; File configFile new File(src/main/resources/generatorConfig.xml); ConfigurationParser cp new ConfigurationParser(warnings); Configuration config cp.parseConfiguration(configFile); DefaultShellCallback callback new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); for (String warning : warnings) { System.out.println(WARNING: warning); } } }这种方式的优越性在于控制力更强。你可以传入自定义的ProgressCallback实时看到每条 SQL 的生成进度还可以在generate(null)阶段做额外的日志记录。Maven 插件本质上也是封装了这段逻辑只是把配置路径和 overwrite 参数暴露成了插件配置项。需要注意DefaultShellCallback的行为当 overwrite 为 true 时它会直接覆盖文件不会做任何备份。所以如果你用 Java 方式生成建议在配置里把输出目录和正式源码目录分离先生成到临时目录人工 review 一遍再同步。3.3 方式三命令行方式命令行方式适合在没有 IDE 的服务器或 CI 流程里自动执行。Maven 插件本身就是命令行友好型但如果你希望独立于项目单独运行也可以使用官方发布的 jar 包java -jar mybatis-generator-core-1.4.2.jar -configfile generatorConfig.xml -overwrite使用前需要确保 classpath 下包含数据库驱动。通常在服务器上执行时我会把驱动 jar 和生成器 jar 放在同一个目录然后运行java -cp mybatis-generator-core-1.4.2.jar:mysql-connector-java-8.0.33.jar \ org.mybatis.generator.api.ShellRunner \ -configfile generatorConfig.xml -overwrite命令行方式的优点不止是脱离 IDE更在于它很适合接入到 git hooks 或者 Jenkins 流水线里。比如项目里约定“所有表结构变更必须执行一次生成”就可以在 CI 脚本里加一个步骤自动生成新表的基础代码然后提交到仓库。这样多人协作时大家拿到的都是同一份生成产物不会出现有人用旧版本、有人用新版本导致的字段缺失问题。3.4 生成结果的检查与验证不论用哪种方式生成完成之后都建议做三件事。第一检查实体类的字段注释是否完整、类型是否符合预期重点看时间字段是不是LocalDateTime、金额字段是不是BigDecimal第二检查 Mapper 接口的方法命名是否可读比如selectByPrimaryKey而不是selectByPrimary不对的就要回头检查表配置第三把工程跑起来的核心验证方式是写一个单测或者直接在 Service 层调用一个简单查询避免启动时才发现 Mapper 扫描包路径没有覆盖到新生成的位置。我之前带过一个同事生成后直接把文件放进项目里结果运行时报 SQL 映射找不到。查了半天才发现他把sqlMapGenerator的 targetProject 写成了项目根目录XML 文件被生成到了workspace/resources下面压根不在 classpath 中。所以验证环节不能偷懒尤其是第一次配置的时候时间再紧也要走一遍单测。4. 常见问题与排查技巧实录4.1 报错速查表我把这几年用 MyBatis Generator 遇到的报错整理成一张表基本覆盖了大部分常规场景报错信息原因分析解决方案Table xxx doesnt exist连接串里未指定库名或表名大小写问题检查 JDBC 地址MySQL 下确认 useInformationSchema 配置No suitable driver found插件未引入数据库驱动在插件 dependencies 中显式添加 mysql-connector-javaThe specified target project directory X does not existtargetProject 路径不存在或模块路径写错确认目录存在多模块下写清楚模块前缀Cannot connect to database server网络不通、账号密码错、防火墙拦截先用数据库客户端连接验证Unsupported charset连接串缺少 characterEncoding 或数据库字符集特殊连接串加 characterEncodingutf8或调整库字符集Duplicate class name两张表映射了同一个 domainObjectName检查 table 配置避免命名冲突The JDBC driver has been forcibly unregistered高版本驱动未处理驱动反注册一般不影响生成忽略或升级到官方 8.0.33 以上4.2 覆盖与备份机制的正确玩法覆盖问题是所有代码生成工具都绕不开的话题。MyBatis Generator 默认没有备份机制overwritetrue的时候同名文件直接替换。项目中如果已经手写了 Mapper 扩展方法一种常见的做法是把扩展方法写到另一个接口里然后让 Mapper 接口继承它public interface ExtUserMapper { ListUser selectUserWithOrders(Param(userId) Long userId); } public interface UserMapper extends ExtUserMapper { // 生成的 CRUD 方法 }这样即使生成器把 UserMapper 覆盖了扩展方法也不会丢。另一种做法是约定好“生成后不要改动生成的文件”所有的自定义 SQL 都写到独立的 XML 文件里比如user-ext.xml。缺点是手写 SQL 需要自己保证 namespace 不冲突但好处是生成器怎么重新执行都不会影响已有逻辑。从工程管理角度我建议团队内部统一一种方式并在 README 里写明“执行生成器后必须检查 git diff”防止有人误覆盖重要手写代码。生成前顺手git add -A和git commit -m backup before regenerating也是一个我自己的小习惯成本极低收益极高。4.3 大小写敏感、关键字冲突与特殊字段处理MySQL 在 Linux 下表名是区分大小写的Windows/macOS 默认不区分。如果你的开发机是 Windows数据库在 Linux 上很容易出现本地生成正常、线上生成找不到表的问题。此时在 table 配置里显式指定 schema或 tableCatalog能规避大部分问题table schemayour_db_name tableNameuser domainObjectNameUser /table关键字冲突也是老生常谈。比如表字段叫order、group、desc直接生成 SQL 的时候可能出现语法错误。MyBatis Generator 默认会对部分保留字加反引号但为了保险最好在字段映射上手动指定列名别名columnOverride columnorder propertyorderNo /这个配置会改变生成的 Java 属性名和 XML 里的列引用但又不会要求你改数据库字段名。对于order这种保留字生成后的 XML 中 select、insert 语句都会正确添加反引号避免 SQL 执行时直接报错。4.4 多数据源场景下的配置组织很多后台系统会同时连接多个数据库比如主库和报表库。MyBatis Generator 的context节点天然支持多套配置你可以在同一个 generatorConfig.xml 里配置两个context指定不通的 connectionURLcontext idmainDb targetRuntimeMyBatis3Simple defaultModelTypeflat jdbcConnection ... connectionURLjdbc:mysql://localhost:3306/main_db/ javaModelGenerator targetPackagecom.demo.model.main .../ ... /context context idreportDb targetRuntimeMyBatis3Simple defaultModelTypeflat jdbcConnection ... connectionURLjdbc:mysql://localhost:3306/report_db/ javaModelGenerator targetPackagecom.demo.model.report .../ ... /context运行一次mvn mybatis-generator:generate会按顺序执行两个 context。这里需要注意有时两个库存在同表名、同字段名生成的每个 context 都要单独确认 targetPackage 不重复否则容易出现重复类编译失败。另外不同数据库方言的表注释查询方式不一样像 Oracle、PostgreSQL、SQL Server 的方言配置都和 MySQL 不同项目里如果同时接多种数据库要分别为每个 context 调整类型解析器。4.5 代码生成之后运行时报错的快速定位法生成只是第一步生成后的代码是否真的能跑通是更重要的一关。运行时报错最常见的三类org.apache.ibatis.binding.BindingException: Invalid bound statement (not registered)。这代表 Mapper 接口和 XML 文件没有正确绑定。排查链路是先确认 XML 的 namespace 要与接口全限定名一致再看 XML 文件是否在 classpath 下最后看 MyBatis 配置里的 mapperLocations 是否包含对应路径。java.lang.ClassCastException: java.sql.Timestamp cannot be cast to java.time.LocalDateTime。这个通常是类型处理器缺失。如果用 JSR310 类型又没引入对应的 mybatis-typehandlers-jsr310 依赖或者 MyBatis 版本低于 3.4.5任何 LocalDateTime 字段都可能出问题。Unknown column create_time in field list。这种多半是配置文件里启用了列名和属性名的严格映射但生成的 XML 中使用了默认命名策略实际插入语句里出现了错误的列名。排查方向集中在 table 配置里是否启用了useActualColumnNames、enableInsert等。排查工具层面推荐开启 MyBatis 的 SQL 日志来观察生成的语句比如logging: level: com.demo.mapper: debug把 Mapper 包日志级别开到 debug控制台会输出每条 SQL 的 PreparedStatement 参数能清晰定位是列缺失还是参数没传进去。这个方法比反复阅读 XML 要快得多。5. 让生成结果更贴合项目规范的进阶手段5.1 自定义注释方案默认注释生成出来的东西长这样/** * This class was generated by MyBatis Generator. * This class corresponds to the database table user * generated Wed Jun 01 10:00:00 CST 2022 */每次生成时间都不一样代码评审时 diff 很大。自定义注释的方式是继承 DefaultCommentGenerator 并重写 addModelClassComment 和 addGeneralMethodComment 等几个方法。一个基本实现package com.demo.mybatis.generator; import org.mybatis.generator.api.CommentGenerator; import org.mybatis.generator.api.IntrospectedTable; import org.mybatis.generator.api.dom.java.*; import org.mybatis.generator.internal.DefaultCommentGenerator; import java.util.Properties; public class CustomCommentGenerator extends DefaultCommentGenerator { private final String author team-code; Override public void addModelClassComment(TopLevelClass tc, IntrospectedTable introspectedTable) { tc.addJavaDocLine(/**); tc.addJavaDocLine( * introspectedTable.getRemarks()); tc.addJavaDocLine( *); tc.addJavaDocLine( * author author); tc.addJavaDocLine( * date LocalDate.now()); tc.addJavaDocLine( */); } Override public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) { method.addJavaDocLine(/**); method.addJavaDocLine( * method.getName()); method.addJavaDocLine( */); } }然后在 generatorConfig.xml 的commentGenerator节点指定全限定类名commentGenerator typecom.demo.mybatis.generator.CustomCommentGenerator/这种自定义的好处不只是注释好看更关键的是可以按团队规范统一字段说明。上面代码里introspectedTable.getRemarks()会读取表注释这个动作依赖 JDBC 连接里useInformationSchematrue。如果没有设置这一项这里拿到的往往是一个空字符串所以注释生成和 JDBC 配置是联动关系。5.2 自动补充逻辑删除与乐观锁字段实际业务表里基本都会有逻辑删除字段is_deleted和版本号version。MyBatis Generator 不会自动识别这些字段的业务含义但可以通过在实体里额外生成方法来统一处理。比较轻量的做法是使用自定义插件在生成的 Model 类里增加默认值设置package com.demo.mybatis.generator.plugin; 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.TopLevelClass; import java.util.List; public class DefaultValuePlugin extends PluginAdapter { Override public boolean validate(ListString warnings) { return true; } Override public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable) { if (isDeleted.equals(introspectedColumn.getJavaProperty())) { field.setInitializationString(0); } if (version.equals(introspectedColumn.getJavaProperty())) { field.setInitializationString(1); } return super.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable); } }配置到生成器后新生成的实体里 isDeleted 字段默认值是 0version 字段默认值是 1。这个插件不需要每个项目都写一遍建议沉淀到团队的公共模块里做成二方库引入这样新项目接入时直接复用。类似的场景还有“创建时间自动填充当前时间”可以在 insert 语句生成时通过 SQL 片段控制不一定非要在生成器层面做用数据库 DEFAULT CURRENT_TIMESTAMP 更省心。5.3 多表关联查询的补充策略MyBatis Generator 是单表代码生成器它不会帮你生成 join 查询。但业务系统不可能都是单表操作所以在团队中我形成了这样的分工单表 CRUD用生成器产物直接完成。两表以上 join 的只读查询在独立的扩展 XML 里手写 SQL复用生成的 ResultMap 做映射。复杂写操作批量插入、批量更新、insert or update在手写 SQL 的基础上配合自增主键回填。复用 ResultMap 这一点很容易被忽略。如果你在user-ext.xml里又写了一个resultMap idUserWithRoleMap然后发现和生成的 UserMapper.xml 里字段映射不一致排查起来非常痛苦。正确做法是手写 SQL 的resultMap直接引用生成好的BaseResultMap结构统一字段不会丢。如果你用的是注解方式也可以在 Mapper 接口里写ResultMap(com.demo.mapper.UserMapper.BaseResultMap)这样手写Select查询也能复用生成的字段映射关系。5.4 增量生成与表结构变更的协同流程数据库表结构是不断变化的今天加一列明天改一个字段类型生成器必须能应对这种“增量变更”。这里要明确一点MyBatis Generator 是整体覆盖不是增量合并。也就是说它不会智能地保留你新增的手写方法只会按照当前表结构重新生成一份文件。所以表结构变更时标准的处理流程是先检查当前分支的 git 状态确认没有未提交的手写改动落在将要被覆盖的文件里。先执行一次 git diff 备份当前生成文件的内容方便出问题时恢复。运行生成器然后立刻 review 所有 diff重点看新增字段的映射和类型转换是否符合预期。如果只是新增了一个字段生成器会更新实体类和 XML 的 ResultMap、Base_Column_List 等位置手写的扩展查询不需要改动因为它引用的是 ResultMap 的 id而 id 不会变。如果删除了某个字段一定要排查手写 SQL 中是否还用到该列否则运行期会报 Unknown column。增量生成的另一个细节是小版本升级问题。生成器的版本升级后生成的格式可能会变化例如注释风格、XML 缩进、方法顺序等。升级后第一次生成diff 会非常大但大多只是格式层面的差异。这种时候建议不要一次性把生成结果全部提交而是先用临时目录生成人工比对确认业务影响。5.5 与 MyBatis-Plus 生成器互换的参考很多团队现在用的是 MyBatis-Plus它的代码生成器MybatisPlusGenerator也能生成实体、Mapper、XML而且默认带有逻辑删除、乐观锁注解。这里补充一句如果你的项目已经引入 MyBatis-Plus直接用它自带的生成器会更省事如果项目还在用原生 MyBatis 并且不想为此引入一套 ORM 增强框架那么 MyBatis Generator 依然是轻量可靠的选择。两者互换有一个常见问题MyBatis-Plus 生成的实体默认标注TableName、TableId等注解而原生 MyBatis Generator 生成的实体完全靠 XML 描述映射关系。如果团队中间切换过框架数据库表名和 Java 字段映射就很容易出现二义性。所以我个人的建议是团队框架选型确定后就不要再无谓地切换生成器哪怕功能上 MyBatis-Plus 生成器更全面频繁切换的迁移成本远大于工具本身带来的收益。如果你实在想用 MyBatis-Generator 生成模型再交给 MyBatis-Plus 做操作也不是不行但要做好TableName注解依赖和默认驼峰映射的匹配这又是一个不小的工程。6. 实操心得从“能用”到“好用”的关键一跃按照整篇笔记的顺序走下来其实你会发现 MyBatis Generator 本身的学习曲线并不陡关键在于能不能把“生成”这个动作融入整个项目的开发规范里。在我所在的团队我们制定的规范大概是这样所有基础单表 CRUD 一律使用生成器产物禁止手写重复的insert、updateByPrimaryKey这类方法。手写的扩展 SQL 必须放到独立 XML 或使用注解方式实现绝不直接修改生成文件。表结构变更后必须由 DDL 提交人在 24 小时内执行一次生成器并提交 diff避免其他人依赖旧结构写出错误代码。生成器配置文件和自定义插件统一提交到项目工程里作为基础设施管理不允许各人本地私藏一套配置。这个规范执行了大概半年最大的感受就是大家代码里“低级查询”的写法变得非常一致评审代码时可以更集中地关注业务逻辑而不是浪费在“这里为什么不用 selectByPrimaryKey”这种事情上。另外因为生成产物是标准化的团队在培训新人时的负担也小很多。最后有机会的话可以再跑一次mvn mybatis-generator:generate然后用 git 看看 diff 里到底发生了什么变化你能更直观地理解这个工具的每个配置项带来的真实影响。其他再深的东西比如插件 API 文档、自定义类型解析器用到的时候再按官方文档补就行不需要一开始把每个扩展点都啃一遍。
返回列表