1. 项目背景与工具选型思路
1.1 为什么数据库建模阶段值得认真对待
做后端开发这些年,我见过太多团队在数据库设计上栽跟头。有的项目一上来就写建表SQL,边写边改,表结构随意加字段,等业务跑起来之后发现数据关系乱成一团,再回头梳理成本已经很高了。数据库表结构是一个系统最底层的地基,地基没打稳,上层业务代码再漂亮也没用。
我接触PDManer(也叫PDMan)纯属偶然。当时在一个新项目里需要快速搭建一套包含几十张表的数据模型,手头用过的工具各有各的别扭:有些商业建模工具功能全但重,授权成本也高;有些在线工具用起来方便,但表一多、关系一复杂就卡顿,而且数据存在别人服务器上总有点不放心。朋友推荐了PDManer这个开源工具,一试就用到了现在。
PDManer本质上是一款国产开源的数据库建模工具,定位非常明确:把数据库表结构设计、ER图绘制、建表SQL生成、代码生成这几件事串成一条流水线。它支持MySQL、PostgreSQL、Oracle、SQL Server等主流数据库,既可以反向从已有数据库导入表结构,也可以正向从模型生成建表语句。最让我看重的一点是,它生成的代码不只是模板拼接,而是可以高度自定义的,甚至有插件机制。
这个工具解决的痛点其实很朴实:不让数据库设计停留在文档或者某个人脑子里,而是变成一个真正可编辑、可版本管理、可自动产出上下游产物的核心资产。无论是个人开发小项目,还是团队协作的中大型系统,建模这一步做得扎实,后面写Mapper、写实体类、写接口文档的时候都会省下大量时间。
1.2 PDManer 与市面上其他建模工具的区别
很多朋友问我,为什么不直接用Navicat或者MySQL Workbench画ER图呢?我的看法是,工具之间不是简单的谁替代谁,而是看你在哪个阶段需要什么能力。
Navicat这类数据库客户端,核心是日常数据操作和管理,它也有简单的模型设计功能,但相对单薄。比如你要在一张表上配置一个枚举类型的说明、一个默认值的表达式、一个字段的“是否主键/唯一/自增”组合规则,操作路径并不顺畅。更重要的是,Navicat是付费商业软件,团队全员安装授权是一笔不小的开销。
MySQL Workbench免费,建模能力也不错,但如果你用的是PostgreSQL或者国产数据库,它就没那么通用了。而且它的模型文件(.mwb)是二进制格式,团队成员之间做代码评审、模型对比非常困难,文件多版本冲突时几乎无法合并。
PDManer的模型文件是json格式,这点非常贴合开发者的习惯。JSON天然适合做版本管理,Git里可以逐行追踪模型字段的变更历史,这对我来说是刚需。另一个让我放心的点是它是本地应用,模型数据存在自己的项目目录里,不依赖云端,对数据安全要求高的项目尤其友好。
在建模能力上,PDManer提供了完善的逻辑模型和物理模型支持、索引/约束/默认值/注释等完整字段属性配置、ER图自动布局和手动调整、版本间的模型对比与升级脚本生成,这些功能覆盖了我在全流程建模中的绝大部分需求。配合代码生成功能,基本可以做到“模型一改,实体类、Mapper、XML、Service等代码同步更新”,非常顺手。
2. 建模核心流程拆解与实操要点
2.1 从需求到数据模型的思考路径
拿到需求之后,我不建议立刻打开工具画表。建模的第一课是“先思考,后建模”。我自己习惯按三步走:先梳理业务实体,再确定实体间关系,最后落字段明细。
业务实体怎么找?很简单,看业务描述里的名词。比如“用户”“订单”“商品”“支付记录”——这些名词大概率是核心实体。名词找出来之后,再想想哪些是真正的核心实体,哪些只是某个实体的属性。比如“收货地址”,最初看起来像是一个独立实体,但如果你细想,一个用户可能有多个地址,而且地址在订单里是快照式的存在(下单时的地址不能被后续修改影响),那么它就应该拆成独立表。这一类的判断,直接决定了模型的结构是否合理。
实体之间关系我用最朴素的方式画:一对一、一对多、多对多。在PDManer里,我通常先把多对多关系拆成中间表,这样后续生成的SQL和ORM映射都会简单很多。比如“用户”和“角色”是多对多,我会创建一个“用户角色关联表”,里面放用户ID和角色ID,再附上创建时间之类的审计字段。
字段明细设计时,我习惯给自己列几条硬性规则:
- 每个实体必须有主键,主键尽量用自增ID或用雪花ID这类分布式ID,不要用业务字段当主键。
- 所有表必须有创建时间、更新时间,这两个字段在排查数据问题和做增量同步时太重要了。
- 金额、数量等数值字段,一定要先搞清精度要求,用DECIMAL而不是FLOAT/DOUBLE,避免浮点误差。
- 状态字段要单独拎出来想清楚:状态的取值集合是什么、谁负责流转、要不要记录历史轨迹。
这些规则看起来基础,但实际项目中因为违反它们而返工的例子比比皆是。树形结构没设计好、枚举值直接魔法数字写死在代码里、软删除字段类型不统一……这些坑在建模阶段就可以规避掉大部分。
2.2 实体、字段、关系设计的关键细节
在PDManer里新建一个数据表,界面不会给你压力,但你要在里面填的东西值得认真对待。
字段设计页里,我看到很多初学者只填字段名和类型就完了。真正合理的做法是:每个字段都要写“注释”。这个注释不是给数据库看的,是给半年后的自己和团队同事看的。比如一个字段名叫status,如果不写注释,没人知道0、1、2分别代表什么;写了“状态:0-待支付 1-已支付 2-已取消”,后面写代码和查数据都会舒服很多。PDManer生成的建表语句中,注释会完整保留成SQL里的COMMENT,直接同步到数据库,这个习惯受益无穷。
类型选择上,不同数据库差异很大。PDManer里可以选择对应的数据库类型,它会给出符合该数据库语法的字段类型列表。比如在MySQL里用DATETIME,在PostgreSQL里用TIMESTAMP,在SQL Server里用DATETIME2,这些细微差异工具会帮你兜底。但你要理解背后逻辑:时间字段如果涉及跨时区业务,最好统一存UTC并在应用层转换;如果只是本地单时区业务,用数据库本地时间即可。
关系的设计在PDManer里通过“外键”体现。但我建议:逻辑上要有关系,物理上建不建外键约束视情况而定。在互联网高并发场景,物理外键会影响写入性能,而且一旦数据量大后维护困难。所以我在PDManer里会明确画出关系连线,但生成SQL时经常选择“外键只体现在关系图中,不实际生成外键约束”。这个取舍我在后面生成SQL的章节还会详细说。
索引设计是建模中很容易被忽略但极其影响查询性能的一环。PDManer中每张表都可以单独配置索引,包括普通索引、唯一索引、组合索引。我自己的原则是:唯一约束尽量用唯一索引表达;组合索引要遵循“最左前缀”原则,把区分度高的字段放前面,把范围查询字段放最后;避免每个字段都加索引,因为索引不是免费的,写入时要更新索引B+树,索引过多会拖慢写入速度。
2.3 数据类型与命名规范:踩坑基础
命名规范是我在建模时最坚持的一件事。表名、字段名的风格统一,会让后续所有环节(SQL编写、ORM映射、代码生成)顺利很多。我推荐这套规则:
- 库名、表名、字段名一律小写,单词间用下划线分隔,不混用驼峰。
- 表名用业务模块前缀,比如订单模块的表以
ord_开头,用户模块以usr_开头,一眼能看出归属。 - 字段名避免使用数据库保留字。
order、user、desc、level这类词在MySQL 8中会带来意想不到的麻烦,如果实在躲不开,至少要用反引号兜底,但最好前期就改名,比如订单表叫ord_order,订单状态字段叫ord_status。 - 主键固定叫
id,关联字段用xxx_id格式,比如user_id、order_id,这样ORM映射时无需额外配置也能猜出大半。
数据类型那边我再提一个容易踩的坑:文本字段长度。很多人图省事,对所有文本字段统一用TEXT或者VARCHAR(255)。这带来的直接问题是索引失效——MySQL里TEXT类型不能直接在非前缀索引下用,VARCHAR(255)又浪费空间且可能超出索引限制。我的建议是:状态码、短标识用VARCHAR(32),名称类用VARCHAR(64)或VARCHAR(128),备注类说明用VARCHAR(500),真正超长内容才用TEXT。PDManer里字段长度直接可配,顺手填一下而已,别偷懒。
3. 实战:用 PDManer 完成一套订单系统建模
3.1 创建项目与数据源配置
光讲理论不过瘾,我拿一个实际的小型订单系统来演示完整建模过程。这套系统不用太复杂,但典型场景要覆盖到:用户、商品、订单、支付、售后,再加一张审计日志表,一共六张表,足够说明问题。
打开PDManer,第一步新建项目。项目名称填“order-system”,技术类型选择“MySQL 8.x”,PDManer会自动按MySQL 8的方言处理后面的SQL生成。这里有个细节:技术类型尽量一次性选对,虽然中间可以改,但改完之后字段类型映射可能会需要手动调整。
项目创建后,左侧会出现一个层级树:包/模块下面的数据表列表。PDManer里的“模块”概念非常好用,比如我可以建“用户模块”“订单模块”“商品模块”三个包,把对应表拖进去,模型文件大了以后找表就不用滚动了。
数据源配置这块,PDManer支持从已有数据库反向同步表结构。如果你手上是已有项目,就可以通过“从数据库导入”直接生成模型。操作路径是:右侧工具栏找到“从数据库导入”,填上数据库连接信息,勾选要导入的表,PDManer会读取表结构、索引、注释,自动生成对应的模型。我做老项目维护时经常用这个功能,省去了手动录表结构的大量时间。
3.2 核心表结构设计实操
我会在“用户模块”下新建表。PDManer建表流程非常直接:输入表名usr_user、表注释“用户表”,然后开始加字段。用户表我会这样设计:
id:BIGINT,主键,自增,注释“用户ID”username:VARCHAR(50),唯一索引,注释“登录名”password_hash:VARCHAR(64),注释“密码哈希值”nickname:VARCHAR(50),注释“昵称”phone:VARCHAR(20),可空,注释“手机号”email:VARCHAR(100),可空,注释“邮箱”status:TINYINT,默认值1,注释“状态:0-禁用 1-正常”created_at:DATETIME,默认值CURRENT_TIMESTAMP,注释“创建时间”updated_at:DATETIME,默认值CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,注释“更新时间”
字段填写时,留意PDManer的“默认值”输入框。它不只是一个文本箱,你填CURRENT_TIMESTAMP,生成SQL时就会原样输出;如果填一个普通字符串,工具会自动按数据库类型加引号,这个细节能避免很多默认值生成的语法错误。
订单表ord_order是核心中的核心,字段会比用户表多。我给出几个关键字段及设计考量:
order_no:VARCHAR(64),唯一索引,注释“订单编号”。订单编号作为业务标识必须唯一,但不要做主键,因为即便用了雪花ID,也不排除用户服务按单号查询,给它加唯一索引就够了。user_id:BIGINT,注释“下单用户ID”。这里就是一对多关系的外键字段,我在设计层面建立到usr_user.id的关系连线,但生成SQL时不一定生成物理外键约束。total_amount:DECIMAL(10,2),注释“订单总金额”。金额用DECIMAL而不用FLOAT。pay_status:TINYINT,注释“支付状态:0-未支付 1-已支付 2-已退款”ship_status:TINYINT,注释“发货状态:0-未发货 1-已发货 2-已签收”address_snapshot:TEXT,可空,注释“收货地址快照,JSON格式”。这是快照设计,下单时把地址和商品信息沉到订单里,避免后续地址变更影响历史订单。
商品表prd_product、支付表pay_payment、售后表aftersale_log、操作日志表sys_audit_log也照此设计。整个建模过程中,我一边建表一边通过ER图查看关系连线是否正确,PDManer的ER图可以手动拖拽排列,我习惯把核心表放中间,关联表放四周,一眼看过去清晰明了。
3.3 关系图与逻辑校验
表建完之后,PDManer的“关系图”功能就可以派上用场了。关系图就是ER图的动态版本,你可以在画布上拖拽表、连线、分组。画布上双击表还能直接跳到字段编辑,修改字段之后关系图实时刷新。
建立外键关系的操作是:从表A的字段拖到表B的字段,比如从ord_order.user_id拖到usr_user.id,PDManer会自动识别关联并弹窗让你确认关系类型。这时候要注意一个细节:关系类型要选“多对一”还是“一对多”,它会影响后续生成代码时嵌套对象的生成顺序。从订单到用户是多对一,从用户到订单是一对多。如果搞反了,生成的Java实体类可能就是订单列表里嵌套用户列表,完全不符合业务直觉。
逻辑校验是很多用户忽略的功能。PDManer菜单里有“检查模型”之类的能力,我建议在建模收尾时跑一遍。它能检查出主键缺失、字段名重复、关系引用不存在的表等问题。虽然不能保证模型100%合理,但至少把低级错误挡在生成SQL之前。我每次建模结束都会跑一次校验,心里才有底去生成脚本。
3.4 生成建表语句的三种方式
PDManer生成建表SQL有三种方式,我分别说下适用场景。
第一种是单表生成。在表节点上右键,选择“生成SQL”或者“查看SQL”,只输出当前这张表的建表语句。适合快速查看某一两表的结构,不用把全部表的结构都刷出来。
第二种是整库生成。选中项目根节点右键生成,会把所有表、索引、注释、外键约束全部输出到一个SQL文件里。适合初始化数据库。这里可以选择是否包含“建库语句”、“DROP TABLE IF EXISTS”、“外键约束”等选项。我强烈建议只在初始化脚本里包含DROP语句,稍后单独维护的增量脚本千万不要执行DROP,否则线上数据直接没了。
第三种是版本间差异生成。如果你修改了模型,PDManer可以和上一个版本对比,只生成增删改的SQL。这个功能在线上环境表结构升级时非常关键。它的操作在“版本管理”里,确定旧版本和当前版本后,工具会自动分析出新增表、新增字段、修改字段、删除字段,并生成对应的ALTER语句。我用它来生成迁移脚本,比手写ALTER靠谱得多。
生成SQL前有几个选项值得留意:
- “包含外键约束”:如果生产环境性能吃紧,或者你根本不想在数据库层面用外键,就取消勾选,关系只是模型层的逻辑关系,不会落到物理外键。
- “生成注释”:保持勾选,字段注释会作为SQL注释输出,而且是带
COMMENT语法的,对后来接手的人特别友好。 - “格式化SQL”:PDManer默认生成的SQL就挺规范,但不同版本可能有细微差异,建议保留这个选项,输出的SQL要能直接在Navicat或者命令行工具里跑通。
生成的SQL示例长这样(MySQL方言):
CREATE TABLE `ord_order` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '订单ID', `order_no` varchar(64) NOT NULL COMMENT '订单编号', `user_id` bigint NOT NULL COMMENT '下单用户ID', `total_amount` decimal(10,2) NOT NULL COMMENT '订单总金额', `pay_status` tinyint NOT NULL COMMENT '支付状态:0-未支付 1-已支付 2-已退款', `ship_status` tinyint NOT NULL COMMENT '发货状态:0-未发货 1-已发货 2-已签收', `address_snapshot` text COMMENT '收货地址快照,JSON格式', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`), KEY `idx_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';这段SQL直接扔进数据库就能执行。表名、字段名、注释、索引、字符集全都齐了,基本不用二次修改。
4. 代码生成模块的完整落地
4.1 模板配置与通用代码生成
模型建好只是第一步,真正让PDManer高效的时刻是从模型直接生成代码。它内置了代码生成引擎,可以根据表结构自动生成实体类、Mapper接口、Mapper XML、Service、Controller等常见代码。这个功能背后其实是一套模板系统,默认模板覆盖了Java + MyBatis这套常见组合,也支持自定义模板,意味着你可以按自己的技术栈生成任何文本文件。
第一次打开代码生成功能时,左侧会让你选择数据库表,右侧是模板列表。PDManer预置了一些模板,比如一个“MyBatis3”模板,它会针对每张表生成对应的DO类、Mapper接口和XML文件。你还可以选择生成到哪个目录,以及包名、基础路径等参数。
这里要给新手一个减负提示:默认模板生成的代码只能算“骨架”,别期待它一步到位生成无敌业务逻辑。它的价值在于你不再需要手写那些繁琐又雷同的实体属性和CURD基础方法,而是可以把精力集中到真正的业务实现上。比如表里字段是user_id,生成的实体类属性会自动变成userId,类型自动对应Java类型的Long和String,空值策略、注释都对得整整齐齐。对我来说,省掉最烦的部分才是关键。
4.2 自定义模板改造
PDManer的代码生成真正拉开差距的地方是“自定义模板”。默认模板未必匹配你团队的技术栈,比如你们用的是MyBatis-Plus,或者JPA,甚至用了自研的ORM框架。这些情况下,你要学会写模板。
PDManer的模板语法很像FreeMarker:用${表名}、${字段名}这类占位符引用模型信息。你可以在“代码生成”面板里新建模板,然后定义输出文件的类型(Java文件、XML文件、文本文件)、文件后缀、内容模板。模板里可以遍历当前表的字段列表、主键字段、关系字段等。
我举个例子。假设团队要求所有实体类继承一个BaseEntity,并且Swagger注解必须写到每个字段上。默认模板没有这个逻辑,我就自己写一段:
package ${packageName}.entity; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.time.LocalDateTime; @Data public class ${tableNameCamelCase} extends BaseEntity { private static final long serialVersionUID = 1L; <#list table.columns as column> @ApiModelProperty(value = "${column.comment}") private ${column.javaType} ${column.javaFieldName}; </#list> }简单解释一下:${packageName}是包名,${tableNameCamelCase}是表名转成的驼峰类名,table.columns是字段列表,column.comment、column.javaType、column.javaFieldName分别是字段注释、Java类型、驼峰属性名。有了这个模板,下次再建表,生成实体类时Swagger注解、Lombok注解、继承父类全都自动带上,团队规范就通过模板固化下来了。
自定义模板还有个妙用:生成前端代码。我们团队前端用的Vue + Element UI,列表页、表单页其实非常套路化。我写了一个模板,把表字段自动映射成Form表单的el-form-item,再配上字段必填校验、输入框、下拉框。模型一变,前端表单CRUD页也几乎同时变。这在项目快速迭代期尤其爽,前后端联调基本不会因为字段对齐问题反复扯皮。
4.3 增量更新与版本管理
代码生成的另一个痛点是怎么做增量更新。很多人担心:模型字段改了,生成代码会不会把之前手写的业务逻辑覆盖掉?这个担忧合理,但要看你怎么用。
我自己的策略是:把生成目录和手写目录分开。比如生成的实体类放在entity/generated目录,手写的扩展类放在entity/ext目录。生成的实体类严格只包含字段和getter/setter,手写业务放扩展类里,这样重新生成时删除generated目录再生成即可,不会破坏任何手写代码。
版本管理维度,PDManer的模型文件是JSON,天然适合Git。我会把模型文件提交到代码仓库,放在docs/database-model目录下,每次字段变更都带上模型文件的修改记录。团队成员拉下来后用PDManer打开,可以看到最新表结构。相比传统方式——靠口头传达“数据库我加了个字段”——这种把模型当代码一样做版本管理的方式,信息断层和沟通成本都大大降低。
模型文件里还隐藏了很多元数据,比如字段顺序、注释、关系连线。这些元数据通过Git diff能看到非常清爽的变更记录,代码评审时我看模型PR比看SQL脚本PR更直观,因为模型文件不会出现“某人手滑改错了个别字段名”这种低级问题。
5. 常见问题与排查技巧实录
5.1 连接数据库失败
PDManer“从数据库导入”或者“同步数据库”时连接不上,这是最高频的问题,我自己也踩过。
排查顺序建议这样来:
第一,确认数据库地址、端口、用户名、密码是否正确。尤其是密码里有特殊字符时,比如@、#,要在连接串里转义,或者在PDManer弹窗中直接原样填,不要先复制到文本编辑器再粘贴(有时编辑器会自动把特殊字符转换成全角,那必挂)。
第二,确认数据库是否允许外部连接。MySQL默认只监听localhost,你要确保有远程访问权限,或者你就在数据库本机用PDManer连接。检查方法是在数据库机器上执行连接测试,排除端口被防火墙拦截的情况。
第三,确认驱动是否正确。PDManer内置了各数据库的驱动,但如果你连的是某些国产数据库(很多兼容MySQL协议但实际端口不同),需要手动添加驱动。比如人大金仓的默认端口是54321,PostgreSQL的驱动并不一定能识别它。在PDManer的设置里可以手动上传JDBC驱动jar包,这一步需要提前准备。
5.2 生成SQL在特定数据库报错
同一个模型,MySQL下完美生成,切到Oracle或者PostgreSQL就报错,这种问题我遇到不止一次。常见原因有两个:字段类型映射不完整,以及默认值写法不兼容。
字段类型方面,PDManer的技术类型切换之后,字段类型映射表不一定完全覆盖你已有的类型。例如TINYINT在Oracle里不存在,它可能映射成NUMBER(3),但如果字段长度设置得不对,生成的NUMBER精度可能和你预期不符。解决方法是:切技术类型后,逐字段检查一遍类型映射,尤其是日期、布尔、大文本、金额这几类。
默认值写法在不同数据库差异巨大。最常见的是布尔类型:MySQL里可以用DEFAULT b'0'或DEFAULT 0,但在PostgreSQL里布尔量词是TRUE/FALSE,SQL Server里又不一样。PDManer在切换类型后一般会自动修正显式表达式,但如果你在默认值里手写了函数,比如CURRENT_TIMESTAMP在Oracle里是不存在的,Oracle要用SYSTIMESTAMP或触发器。这类问题只能人工关注,工具不会替你决策。
我的建议是:从一开始就确定目标数据库,不要试图做一个“全数据库通用模型”。如果确实要支持多数据库,在模型里用标准的、各库兼容度高的功能子集,比如时间默认值统一在应用层或建表后再处理,不依赖数据库侧默认值。
5.3 外键关系生成错误
关系连线画了,生成的SQL里外键却对不上,这也是个常见情况。表现形式有几种:外键引用的表还没创建、外键字段和主键字段类型不一致、外键名重复。
第一种情况比较好排查:生成SQL时会按依赖顺序输出建表语句,但如果你有两个表互相引用(循环依赖),PDManer生成时可能选择一个保守的顺序,结果就是先建的表引用后建的表,数据库直接报错。解决方法是在模型里尽量避免循环依赖,真避免不了就用逻辑外键不加物理约束。
第二种情况非常隐蔽:关系连线的两个字段肉眼看着都是id,但一个是BIGINT,一个是INT,数据库不允许这种外键约束。我记得有一次排查了很久,最后发现是同事把订单表的user_id建成了INT,用户表主键却是BIGINT。这里没有捷径,只能逐个关系核对字段类型。
第三种情况一般出现在你复制表后忘了改外键名。PDManer里外键名默认是fk_表名_关联表名之类,复制粘贴新表后,外键名会冲突。生成SQL时数据库提示“Duplicate foreign key name”,这时候去关系图里检查一下,把重复名字改掉即可。
5.4 代码生成乱码与模板问题
Windows环境下,PDManer生成的Java文件偶尔会出现中文乱码,文件内容看着就是一堆问号。这个大概率是文件编码问题。PDManer默认使用UTF-8,但Windows控制台或者你打开文件的编辑器用了GBK。解决方法有两步:第一步,在PDManer的代码生成设置里,检查输出文件字符集,确保是UTF-8;第二步,用VS Code或IDEA打开生成文件时,右下角切换文件编码到UTF-8。如果还是乱码,用Notepad++打开后另存为UTF-8。
模板问题更多是语法上的。模板写错时,PDManer一般会给出错误提示,但提示信息不够直观。我的经验是:先用最小可用的模板跑通,再逐步叠加复杂语法。比如先只输出${tableNameCamelCase}这个变量,确认能拿到值,再尝试遍历字段。每次只改一点点,出问题也知道是哪里改错了。
5.5 团队协作中的模型同步
多人同时编辑同一个PDManer模型文件,合并冲突在所难免。因为模型文件是JSON,虽然可以用Git处理,但一个字段改动可能引起JSON大段重排,导致合并冲突看起来非常吓人。
我摸索下来比较好用的协作方式是这样的:
- 项目模型拆分成多个文件。PDManer支持“模块”概念,每个模块可以单独导入导出模型文件。我的建议是:大项目按业务域拆文件,每个业务域一个模型文件,避免所有人在同一个文件里挣扎。
- 建表的负责人要明确。一张表尽量只有一个人负责设计,其他人有需求走评审,不要同时开两个人去改同一张表。
- 利用PDManer的“模型对比/合并”能力。如果有两个人确实改到了同一文件,可以从Git拉取后,把对方的模型文件导入当前项目,用对比功能查看差异,再决定如何合并。这比直接打开文件乱改要安全得多。
6. 实用心得与效率技巧
6.1 我日常建模的推荐工作流
用了很长时间PDManer之后,我总结了一套稳定的工作流,分享给想要上手的读者参考。
第一步,新建项目选好目标数据库类型。哪怕只是先试试,这个选择也尽量定准,因为后续字段类型映射都以它为基准。
第二步,边查需求边建表。我习惯先从核心实体开始,比如订单系统的订单表、用户系统的用户表,先把主链路各表建齐,再去补辅助表和字典表。每建一张表就把字段注释写全,不偷懒。
第三步,画关系连线,跑模型校验。关系连线一定在表全部建完之后统一画,不要在每张表建好就急着连,否则中间改表名、字段名时,连线容易断掉或者指向旧字段。
第四步,生成SQL,在本地环境执行一遍。建表SQL生成后,我在本地数据库执行一次,确认所有表都能创建成功。这一步能提前暴露类型映射、默认值语法、字符集问题。
第五步,配置和微调代码生成模板。把默认模板改成符合团队规范的自定义模板,生成一批代码跑个测试,确认链路通顺。
第六步,把模型文件提交到Git,并在README或者文档里说明模型文件位置和修改规则。
这套流程里,最花时间的其实是第二步,其余步骤都是机械式的快速操作。正确的前期设计,能让你在后续开发阶段几乎不再回头改表。
6.2 模型文档自动化的延伸用法
PDManer本身能生成数据字典文档。菜单里“导出文档”或者“生成数据字典”,可以把模型输出成HTML或Markdown格式,表字段列表、类型、注释、索引、外键关系一目了然。以前给客户或者团队写数据字典文档,纯靠人工排版,现在模型一改,文档重新导出一遍就行,零维护成本。
我还会把生成的Markdown数据字典直接扔进项目的GitHub仓库里,作为技术文档的一部分。这样不仅是开发人员,测试、产品甚至运维都能随时查阅表结构,不用专门去问开发“某字段是什么意思”。这种透明度在团队协作中价值很大,也减少了那些“你帮我看看订单表这字段能不能存空值”的重复询问。
再进阶一点的使用方式:把PDManer模型和接口文档打通。比如给某张表生成Controller和Swagger注解,接口入参出参直接从实体类反射生成,字段注释就来自模型里写的comment。这样前端同事拿到的接口文档里,每个字段的中文含义都是准确的,不会出现代码和文档对不上的情况。
6.3 几个容易忽略却很好用的功能
有几个PDManer的小功能,属于“知道的人一直用,不知道的人一直绕远路”的类型,我说几个。
一个是“字段分组”。当一张表字段非常多(比如配置表、扩展信息表),PDManer允许给字段加分组标签,比如“基础信息”“业务信息”“审计信息”,在字段列表里可以按分组折叠查看,表结构就不会显得很乱。这个功能用于大型表非常舒服。
另一个是“模型版本管理”。在菜单的版本相关功能里,你可以保存当前模型快照,之后任意改动都能和快照对比。我建表时如果拿不准某个设计方案,会先存一下版本,改一版对比看看,不好就切回去。这种试错成本比手改SQL低太多了。
还有“字段导入”。如果你有Excel或者Word格式的已有字段清单,可以通过PDManer的导入功能直接生成表结构,字段名、类型、注释从表格里读取。以前从旧项目迁移表结构时,我拿Excel列字段清单给客户确认,确认完直接导入建模,非常高效。这个功能容易被忽略,但实际使用体验非常爽。
最后还有一个经常被人忽略的点:PDManer的项目文件里其实可以写“项目备注/说明”。我习惯在项目说明里记录建模约定,比如“状态字段用TINYINT,不使用INT”“所有表必须有created_at和updated_at”“金额统一DECIMAL(10,2)”等。新同事加入时打开模型文件就能看到这些约定,比翻文档高效得多。
数据库建模这件事,工具只是手段,关键是建模思路和团队规范。PDManer的魅力就在于,它把这些软性的规范通过模板、模型文件、文档导出固化成了可以复制、可以传承的东西。我用这套方法完成了好几个项目的数据库设计和代码生成,节省的时间非常可观,而且模型的演进历史清清楚楚,什么时候加了字段、为什么加了索引都能从Git提交记录里回溯。如果你还没试过用PDManer管理数据库模型,下一次新建项目时,不妨从一张订单表开始体验一下完整的建模到生成链路。