MyBatis逆向工程:从数据库Schema到可维护Mapper的工程化实践
1. 项目概述为什么“MyBatis逆向工程”不是偷懒捷径而是团队提效的底层基建你有没有经历过这样的场景一个新数据库表上线字段12个关联3张字典表业务接口要查、要改、要分页、要导出——光是手写Mapper XML里的resultMap、sql片段、parameterType声明就得花掉大半天更别说还要同步维护对应的Java实体类、Mapper接口方法签名、Service层调用逻辑。我带过的几个后端小组里新人平均在“写基础DAO层”上卡壳2~3天老手也常因字段名拼错、类型映射漏配、动态SQL条件顺序混乱在联调阶段反复返工。而“MyBatis逆向工程自动生成mapper映射”这件事本质上不是让开发者“不写代码”而是把重复、机械、高错误率、低创造性的那部分工作从人脑中剥离出来交给一套可验证、可追溯、可批量执行的标准化流程来完成。它解决的从来不是“会不会写SQL”的问题而是“要不要把时间浪费在写100遍几乎一样的 标签”上的问题。核心关键词——MyBatis、逆向工程、自动生成、Mapper映射——每一个都指向明确的技术动作MyBatis是持久层框架选型逆向工程Reverse Engineering特指从已有数据库结构反向推导出代码结构的过程自动生成强调零人工干预的脚本化输出Mapper映射则是最终交付物的核心形态包含Java实体类POJO、Mapper接口含注解或XML定义、XML映射文件含SQL与结果集映射规则三件套。它适合三类人刚接手遗留系统的维护者快速理清表-对象关系、中台型项目组统一生成标准DTO/VO/Entity避免各模块自行定义导致不一致、以及需要高频迭代数据模型的SaaS产品团队比如每两周新增一张用户行为日志表必须当天完成接入。这不是给懒人准备的“一键生成器”而是给认真做事的人配备的“防错校验仪”和“产能加速器”。我试过最极端的案例某高校实验室的科研数据管理平台初期由3位研究生协作开发数据库含87张表其中62张为元数据配置表如仪器参数模板、实验流程节点、权限角色映射。手动编写Mapper耗时11人日且上线后发现5处字段类型映射错误tinyint被当成Integer而非Boolean、3处resultMap未处理空值导致NPE。引入逆向工程后同一套配置跑一次12分钟生成全部基础代码人工仅需检查3处业务特殊逻辑如密码字段需加密存储不参与通用查询。后续新增表时运维同学只需改一行配置执行一个脚本新表的CRUD能力就已就绪。这背后不是魔法而是把“数据库Schema”这个唯一可信源通过确定性规则映射到“Java代码结构”这个可执行产物上——中间所有环节都可审计、可回滚、可版本化。所以别再把它当成“黑盒工具”它其实是你团队代码规范的第一道防线。2. 核心设计思路拆解为什么必须放弃“IDE插件一键生成”转而构建可复现的工程化流程很多人第一次接触逆向工程第一反应是打开IDEA装个Free MyBatis plugin右键数据库表点“Generate POJOs And Mappers”几秒钟弹出一堆文件——看起来很美。但我在某次跨团队协作中亲眼见过这套方案翻车A组用插件生成的Mapper接口里方法名是selectByUserIdB组用另一款插件生成的却是findByUserIdC组手写的又是queryUserById。三个模块对接时Service层调用方根本不知道该用哪个方法最后靠文档对齐人工改名耗时两天。更致命的是插件生成的代码不进Git不走CI没人知道它基于哪个数据库快照、用了什么命名策略、是否排除了审计字段。当线上出现NullPointerException时排查路径直接断裂是数据库字段改了是插件版本升级了还是某人本地误操作覆盖了生成文件因此真正可靠的逆向工程必须脱离IDE环境走向工程化、脚本化、版本化。它的核心设计逻辑有三层硬约束第一层是输入源唯一性所有生成动作必须基于一份明确的、版本受控的数据库连接配置JDBC URL、用户名、密码且该配置应存于项目根目录下的generatorConfig.xml或pom.xml的plugin配置块中禁止硬编码在IDE设置里。我坚持要求团队把数据库连接信息抽离成generator.properties文件并通过Maven Profile控制不同环境dev/test/prod的生成目标库这样开发时连本地MySQL测试时连Docker里的测试库完全隔离无干扰。第二层是规则可声明化什么表该生成什么字段该忽略主键怎么识别驼峰命名如何转换这些不能靠插件UI里勾选而必须写成XML或YAML中的显式规则。比如table tableNamesys_user domainObjectNameUser enableCountByExamplefalse enableUpdateByExamplefalse/明确告诉生成器只处理这张表生成的Java类叫User且禁用Example模式避免生成大量冗余的Criteria类。我们曾因没禁用Example在一个200字段的大宽表上生成了17MB的Mapper XML编译直接失败。第三层是输出可追溯化每次生成必须记录元信息——生成时间、数据库版本号SELECT VERSION()、MyBatis Generator版本、所用配置文件的Git commit hash。我在build/generated-sources/mybatis/目录下强制添加GENERATION_LOG.md内容类似Generated at: 2024-06-15T14:22:0308:00 DB Version: MySQL 8.0.33 Generator Version: 1.4.2 Config Commit: a3f9c2d (feat: add user_behavior_log table support)这样当某天发现生成的createTime字段在Java里是Date类型而数据库是datetime(3)就能立刻定位是哪次配置变更引入的问题而不是在历史提交里大海捞针。放弃插件不是拒绝便利而是把“便利”的控制权从IDE厂商手里夺回到开发者自己手中。真正的效率来自确定性而非速度。3. 核心细节解析与实操要点从数据库建模到生成配置的12个关键决策点逆向工程看似“配置好就跑”实则每个选项背后都是对项目长期可维护性的投票。我整理了从数据库建模开始到最终生成代码为止必须亲手拍板的12个关键决策点每个都附带血泪教训。3.1 数据库命名规范下划线转驼峰不是万能解药很多团队默认开启property nameuseActualColumnNames valuefalse/让生成器自动把user_name转成userName。但问题来了user_id转成userId没问题user_id_card呢是userIdCard还是UserIdCard我们曾有个表字段叫is_deleted_flag按规则转成isDeletedFlag但业务语义上它就是个布尔标志应该叫deleted。解决方案是在数据库建模阶段就约定前缀规则。我们强制要求布尔字段必须以is_或has_开头如is_active,has_permission生成时通过columnOverride columnis_deleted_flag propertydeleted javaTypejava.lang.Boolean/显式重命名。这样既保持数据库语义清晰又让Java侧API简洁。3.2 主键策略自增ID与UUID必须区别对待table标签的enableInsertSelective和enableUpdateByPrimaryKey属性表面看是开关实则影响整个DAO层设计哲学。对于MySQL自增主键表如order_info我们开启enableUpdateByPrimaryKeytrue因为业务上必然存在“根据订单ID更新状态”的场景但对于使用UUID作为主键的file_metadata表我们关闭它因为UUID主键极少被业务代码直接修改强行生成updateByPrimaryKey方法反而误导调用方。更关键的是generatedKey配置generatedKey columnid sqlStatementMySql identitytrue/必须精确匹配数据库实际策略否则生成的insertSelective会漏掉主键赋值逻辑导致插入后ID为null。3.3 字段类型映射别让JDBC驱动替你做决定MyBatis Generator默认用JDBC的getJdbcType()推断类型但MySQL的tinyint(1)会被当成TINYINT对应Java的Byte而业务上它99%是布尔值。我们必须用columnOverride强制指定columnOverride columnstatus javaTypejava.lang.Boolean jdbcTypeBIT/同理decimal(10,2)默认映射为java.math.BigDecimal但财务系统要求精度绝对可控我们额外增加javaProperty配置确保生成的getter/setter方法名符合getAmount()而非getDecimalAmount()。3.4 Example模式何时该砍掉这颗“毒瘤”enableCountByExample和enableSelectByExample默认为true会生成XxxExample类及一堆countByExample、selectByExample方法。但真实业务中90%的查询都有明确业务语义如findActiveUsersByDeptId而非泛化的where status ? and dept_id ?。我们规定只有配置表、字典表允许启用Example因其查询模式高度通用业务主表一律关闭。关闭后生成的Mapper接口干净利落且迫使开发人员在Service层显式编写有业务含义的查询方法避免后期满屏xxxExample.createCriteria().andStatusEqualTo(1)的面条代码。3.5 XML与注解二选一XML才是企业级项目的事实标准虽然MyBatis支持Select(SELECT * FROM user)注解方式但逆向工程中我们坚持用XML。原因有三一是XML支持动态SQLif,choose的复杂组合注解里写Select(scriptSELECT * FROM user if testname!nullWHERE name#{name}/if/script)可读性极差二是XML文件可被IDE的SQL插件语法高亮、执行测试注解里的SQL是纯字符串三是XML便于统一管理SQL审核规则如禁止SELECT *必须指定字段列表我们通过SonarQube规则扫描*.xml文件中的select标签自动拦截违规SQL。生成配置中javaClientGenerator的typeXMLMAPPER是唯一选择。3.6 包路径与文件名拒绝“默认包”陷阱javaModelGenerator的targetPackage必须精确到com.xxx.project.entity而非entity。曾有团队图省事设为model结果生成的User.java在src/main/java/model/User.java而Spring Boot启动类在com.xxx.Application导致组件扫描失效。更隐蔽的坑是targetProject路径targetProjectsrc/main/java是常规写法但如果项目是多模块Maven必须写成targetProjectmybatis-generator/src/main/java否则生成文件会跑到错误模块下。我们用mvn mybatis-generator:generate -Dmybatis.generator.overwritetrue命令时永远加-D参数覆盖旧文件避免手动清理残留。3.7 枚举字段处理数据库里存数字Java里要枚举类user_status字段存0/1/2业务上对应DISABLED/ACTIVE/LOCKED。逆向工程不会自动生成枚举必须手动介入。我们的做法是在generatorConfig.xml中配置columnOverride columnuser_status javaTypecom.xxx.enums.UserStatus/然后在src/main/java/com/xxx/enums/下提前创建好UserStatus.java内容为标准枚举public enum UserStatus { DISABLED(0), ACTIVE(1), LOCKED(2); private final int value; UserStatus(int value) { this.value value; } public int getValue() { return value; } }生成器会自动在User实体类中将status字段类型设为UserStatus并在UserMapper.xml的resultMap中添加result columnuser_status propertystatus javaTypecom.xxx.enums.UserStatus/彻底解决类型安全问题。3.8 逻辑删除字段不止是加个TableLogicMyBatis-Plus的TableLogic注解很香但逆向工程不认它。我们必须在生成后手动修改一是在User实体类的deleted字段上加TableLogic二是在UserMapper.xml的sql片段中为所有SELECT语句追加AND deleted 0条件三是在delete语句中将DELETE FROM user WHERE id #{id}改为UPDATE user SET deleted 1 WHERE id #{id}。更稳妥的做法是在generatorConfig.xml中用sql标签定义全局base_where_clause并在每个select的where内引用它确保逻辑删除条件不遗漏。3.9 分页插件兼容PageHelper的page标签必须手写PageHelper的startPage方法只对紧随其后的第一个SELECT生效。逆向工程生成的selectByExample方法若返回ListXxxPageHelper能自动分页但若返回ListXxxWithBLOBs含大字段PageHelper可能失效。我们的对策是在generatorConfig.xml中为含BLOB字段的表单独配置table tableNamearticle enableSelectByExamplefalse/然后手写selectArticleList方法在XML中明确使用page标签包裹SQL并在Java接口中声明返回PageArticle。这样分页逻辑完全可控不依赖PageHelper的“魔法”。3.10 生成文件过滤.gitignore不是万能的生成的代码默认放在target/generated-sources/mybatis/但有些团队会把target/加入.gitignore导致CI流水线拉取代码后无法编译——因为target/是Maven构建产物不应进Git。正确做法是在pom.xml中配置outputDirectory${project.basedir}/src/main/java/outputDirectory让生成文件直落src/main/java并把生成目录加入.gitignore如src/main/java/com/xxx/entity/generated/同时在README.md中注明“运行mvn mybatis-generator:generate生成基础代码”。这样开发者本地可随时重生成CI环境通过Maven生命周期自动触发。3.11 多数据源场景一个配置文件不够用微服务架构下订单库、用户库、商品库物理分离。逆向工程不能共用一个generatorConfig.xml。我们的方案是在项目根目录建generator/子目录下设order-db.xml、user-db.xml、product-db.xml每个文件独立配置对应数据源。执行时用mvn mybatis-generator:generate -Dmybatis.generator.configurationFilegenerator/order-db.xml指定文件。更进一步我们用Maven Profiles绑定数据源mvn mybatis-generator:generate -P order-dbProfile中激活对应配置文件彻底解耦。3.12 生成后代码增强Lombok不是银弹很多人开property nameuseLombok valuetrue/生成的实体类加Data。但Data包含ToString当实体含循环引用如User有ListRoleRole又有ListUser时toString()会栈溢出。我们的实践是关闭Lombok生成改用property nameuseLombok valuefalse/然后在User.java顶部手动加Getter Setter NoArgsConstructor AllArgsConstructor精准控制所需特性。ToString和EqualsAndHashCode必须显式排除关联集合字段如ToString(exclude roles)。提示所有columnOverride配置必须在table标签内部不能写在全局context里否则不生效。这是MyBatis Generator的硬性规则踩过坑才知道。4. 实操过程与核心环节实现从零搭建可落地的逆向工程流水线现在我们进入实操环节。以下步骤基于Maven MyBatis Generator 1.4.2 MySQL 8.0所有命令和配置均经生产环境验证。不要跳步每个环节的参数选择都有明确意图。4.1 环境准备三步锁定最小可行依赖第一步确认JDK版本。MyBatis Generator 1.4.x要求JDK 8但若项目用JDK 17需注意javax.annotation包已被移除必须在pom.xml中显式添加dependency groupIdjavax.annotation/groupId artifactIdjavax.annotation-api/artifactId version1.3.2/version /dependency第二步添加MyBatis Generator Maven插件。注意groupId是org.mybatis.generator不是org.mybatisplugin groupIdorg.mybatis.generator/groupId artifactIdmybatis-generator-maven-plugin/artifactId version1.4.2/version configuration verbosetrue/verbose overwritetrue/overwrite configurationFilesrc/main/resources/generatorConfig.xml/configurationFile /configuration dependencies dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency /dependencies /plugin第三步创建src/main/resources/generatorConfig.xml。这是整个流程的“宪法”必须严格遵循DTD规范。我们采用最简但最健壮的结构?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 properties resourcegenerator.properties/ context idMysqlContext targetRuntimeMyBatis3 defaultModelTypeflat plugin typeorg.mybatis.generator.plugins.SerializablePlugin/ plugin typeorg.mybatis.generator.plugins.ToStringPlugin/ commentGenerator property namesuppressAllComments valuetrue/ property nameaddRemarkComments valuetrue/ /commentGenerator jdbcConnection driverClass${driver} connectionURL${url} userId${username} password${password}/ javaTypeResolver property nameforceBigDecimals valuefalse/ /javaTypeResolver javaModelGenerator targetPackagecom.xxx.entity targetProjectsrc/main/java property nameenableSubPackages valuetrue/ property nametrimStrings valuetrue/ /javaModelGenerator sqlMapGenerator targetPackagemapper targetProjectsrc/main/resources property nameenableSubPackages valuetrue/ /sqlMapGenerator javaClientGenerator typeXMLMAPPER targetPackagecom.xxx.mapper targetProjectsrc/main/java property nameenableSubPackages valuetrue/ /javaClientGenerator !-- 表配置在此处 -- table tableNamesys_user domainObjectNameUser enableCountByExamplefalse enableUpdateByExamplefalse columnOverride columncreate_time propertycreateTime javaTypejava.time.LocalDateTime/ columnOverride columnupdate_time propertyupdateTime javaTypejava.time.LocalDateTime/ /table /context /generatorConfiguration关键点解析plugin引入SerializablePlugin确保实体类实现SerializableToStringPlugin生成toString()方法commentGenerator关闭自动生成注释避免中文乱码但开启addRemarkComments保留数据库字段注释javaTypeResolver设forceBigDecimalsfalse防止decimal全转BigDecimaltable内嵌columnOverride精准控制时间字段类型。4.2 配置文件分离generator.properties的黄金法则src/main/resources/generator.properties内容如下# 数据库连接 drivercom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/my_project?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrueuseSSLfalse usernameroot password123456 # 生成路径绝对路径或相对路径 targetJavaProjectsrc/main/java targetResourcesProjectsrc/main/resources # 命名策略 useActualColumnNamesfalse autoDelimitKeywordstrue # 其他 contextIdMysqlContext这里serverTimezoneAsia/Shanghai是MySQL 8.0必需参数否则连接报错allowPublicKeyRetrievaltrue解决SSL握手问题autoDelimitKeywordstrue让生成器自动给关键字字段如order、group加反引号避免SQL语法错误。所有敏感信息密码绝不硬编码在XML中这是安全底线。4.3 执行生成一条命令背后的完整生命周期在项目根目录执行mvn mybatis-generator:generate -Dmybatis.generator.overwritetrue -X-X参数开启Debug日志能看到每一步执行细节。成功时输出类似[INFO] Scanning for projects... [INFO] [INFO] ------------------ com.xxx:my-project ------------------ [INFO] Building my-project 1.0.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- mybatis-generator-maven-plugin:1.4.2:generate (default-cli) my-project --- [DEBUG] Configuring mojo org.mybatis.generator:mybatis-generator-maven-plugin:1.4.2:generate with basic configurator -- [INFO] Connecting to the Database... [INFO] Introspecting table sys_user [INFO] Generating Record class for table sys_user [INFO] Generating Mapper Interface for table sys_user [INFO] Generating SQL Map for table sys_user [INFO] Saving file User.java [INFO] Saving file UserMapper.java [INFO] Saving file UserMapper.xml [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------注意Introspecting table表示正在读取数据库元数据若卡住说明JDBC连接不通Saving file表示文件写入成功。生成的文件位置src/main/java/com/xxx/entity/User.javasrc/main/java/com/xxx/mapper/UserMapper.javasrc/main/resources/mapper/UserMapper.xml4.4 生成文件精修三处必改的“最后一公里”生成的代码不是终点而是起点。必须手工修改三处第一处Mapper接口的Mapper注解UserMapper.java默认没有注解Spring Boot无法扫描。必须在接口上加Mapper public interface UserMapper { // 方法定义 }或者在启动类上加MapperScan(com.xxx.mapper)二者选一。我们倾向前者因为更细粒度可控。第二处XML文件的namespace与resultMapIDUserMapper.xml中mapper namespacecom.xxx.mapper.UserMapper必须与接口全限定名一致resultMap idBaseResultMap ...的ID必须唯一若多张表生成需确保ID不冲突。我们约定BaseResultMap用于基础字段ResultMapWithBLOBs用于含大字段的映射ID前缀加表名缩写如UserBaseResultMap。第三处实体类的TableName与TableField若项目集成MyBatis-Plus需在User.java上加TableName(sys_user)在字段上加TableField(user_name)否则MP的自动填充、逻辑删除等功能失效。TableField的exist false用于忽略数据库不存在的字段如DTO扩展字段。4.5 CI/CD集成让生成成为构建的自然环节在Jenkins或GitLab CI中将逆向工程纳入构建流程。.gitlab-ci.yml示例stages: - generate - build generate-mapper: stage: generate image: maven:3.8-openjdk-11 script: - mvn mybatis-generator:generate -Dmybatis.generator.overwritetrue artifacts: - src/main/java/com/xxx/entity/** - src/main/java/com/xxx/mapper/** - src/main/resources/mapper/** build-app: stage: build image: maven:3.8-openjdk-11 script: - mvn clean package -DskipTests dependencies: - generate-mapper关键点generate-mapper阶段生成代码并作为artifacts传递给build-app确保编译时代码已就绪。这样每次Push数据库变更脚本如V2024.06.15__add_user_status.sqlCI自动触发生成新代码随构建产物发布全程无人值守。注意mvn mybatis-generator:generate命令必须在compile阶段之前执行否则生成的Java文件不会被编译。Maven生命周期中generate-sources是正确时机因此插件配置中phasegenerate-sources/phase是最佳实践。5. 常见问题与排查技巧实录那些官方文档不会告诉你的17个坑逆向工程最大的挑战不是配置而是问题排查。以下是我在多个项目中积累的真实问题速查表按发生频率排序每个都附带现场诊断命令和修复方案。5.1 问题生成后编译报错“找不到符号”提示UserMapper类不存在现场诊断# 检查生成文件是否真的存在 ls -l src/main/java/com/xxx/mapper/UserMapper.java # 检查Maven是否识别为源码目录 mvn help:effective-pom | grep -A 5 sourceDirectory根因targetProject路径错误文件生成到了target/目录下而Maven只编译src/main/java。修复在generatorConfig.xml中将javaClientGenerator的targetProject明确设为src/main/java而非默认的target/generated-sources/mybatis。5.2 问题生成的User.java中createTime字段类型是java.util.Date但数据库是datetime(3)现场诊断-- 查看字段精确类型 DESCRIBE sys_user; -- 输出create_time | datetime(3) | YES | NULL | NULL |根因MyBatis Generator的javaTypeResolver未适配MySQL 8.0的毫秒精度。修复在javaTypeResolver中添加property nameuseJSR310Types valuetrue/并确保JDK 8这样datetime映射为java.time.LocalDateTime。5.3 问题mvn mybatis-generator:generate执行后无任何输出也不报错现场诊断# 开启Debug日志 mvn mybatis-generator:generate -X | grep -i generator\|error # 检查配置文件路径 ls -l src/main/resources/generatorConfig.xml根因configurationFile路径错误或generator.properties文件名拼错如generator.property少了个s。修复在pom.xml插件配置中用绝对路径测试configurationFile${project.basedir}/src/main/resources/generatorConfig.xml/configurationFile。5.4 问题生成的UserMapper.xml中select语句的resultMap引用BaseResultMap但实际定义的是UserBaseResultMap现场诊断# 检查XML中resultMap定义 grep -n resultMap id src/main/resources/mapper/UserMapper.xml # 检查select中引用 grep -n resultMap src/main/resources/mapper/UserMapper.xml根因table标签未设置domainObjectNameUser导致生成器用默认名SysUserresultMapID变为SysUserBaseResultMap。修复在table中强制指定domainObjectName并确保首字母大写。5.5 问题UserMapper.selectByExample方法返回空List但数据库明明有数据现场诊断-- 手动执行生成的SQL从XML中复制 SELECT * FROM sys_user WHERE status ? AND deleted 0; -- 参数填1看是否有结果根因Example类的createCriteria()默认条件是AND但业务需要OR或deleted字段未在Example中设置导致WHERE deleted null。修复关闭enableSelectByExample手写带业务语义的方法或在调用时显式设置example.createCriteria().andDeletedEqualTo(false)。5.6 问题生成的User.java中userName字段的getter方法是getUsername()而非getUserName()现场诊断# 检查生成器的驼峰规则 cat src/main/resources/generatorConfig.xml | grep -A 5 useActualColumnNames根因useActualColumnNamestrue时生成器用数据库列名user_name直接转user_name→username设为false才启用驼峰转换。修复property nameuseActualColumnNames valuefalse/并确认columnOverride未覆盖该字段。5.7 问题mvn compile报错“程序包com.xxx.mapper不存在”现场诊断# 检查生成的Mapper接口是否在正确包路径 ls -l src/main/java/com/xxx/mapper/ # 检查pom.xml中是否遗漏plugin配置 mvn help:effective-pom | grep -A 10 mybatis-generator根因javaClientGenerator的targetPackage设为mapper但targetProject是src/main/java导致文件生成在src/main/java/mapper/而非src/main/java/com/xxx/mapper/。修复targetPackage必须是完整包名如com.xxx.mapper。5.8 问题生成的UserMapper.xml中insert语句未包含selectKey自增ID返回为null现场诊断-- 查看表结构 SHOW CREATE TABLE sys_user; -- 确认id字段是AUTO_INCREMENT根因table未配置generatedKey或identitytrue写成identityfalse。修复添加generatedKey columnid sqlStatementMySql identitytrue/到table内部。5.9 问题UserMapper.updateByPrimaryKey方法执行后数据库记录未更新现场诊断-- 查看生成的SQL SELECT * FROM sys_user WHERE id 1; -- 手动执行update语句从XML复制 UPDATE sys_user SET user_name ? WHERE id ?;根因table的enableUpdateByPrimaryKeyfalse但接口中仍调用该方法或update语句中WHERE条件漏了主键。修复确认enableUpdateByPrimaryKeytrue并检查生成的XML中update标签的WHERE子句是否包含id #{id,jdbcTypeBIGINT}。5.10 问题生成的User.java中Data注解导致toString()栈溢出现场诊断# 运行单元测试触发toString() User user new User(); user.toString(); // 报StackOverflowError根因实体间存在双向关联Data生成的toString()递归调用。修复关闭useLombok手动添加Getter Setter并用ToString(exclude {roles, orders})排除集合字段。5.11 问题mvn mybatis-generator:generate报错“Cannot resolve symbol MyBatisGenerator现场诊断# 检查插件依赖 mvn dependency:tree | grep -i mybatis-generator根因插件dependencies中未声明mysql-connector-java或版本与JDBC URL不匹配。修复在plugin的dependencies中添加与url中MySQL版本匹配的驱动如MySQL 8.0用8.0.33。5.12 问题生成的UserMapper.xml中resultMap的id标签未生成导致一级缓存失效现场诊断# 检查resultMap定义 grep -A 10 resultMap id\BaseResultMap\ src/main/resources/mapper/UserMapper.xml # 看是否有id columnid propertyid jdbcTypeBIGINT/根因