ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

IDEA集成Screw:数据库设计文档自动生成实践指南

IDEA集成Screw:数据库设计文档自动生成实践指南 做Java后端开发的人大概都经历过这样的场景项目还没上线表格已经几十张了领导隔三差五要一份数据库设计文档。你打开Word一张表一张表把字段名、类型、注释抄进去忙活大半天结果产品一句话改了个字段文档又对不上了。后来我在一个老项目里翻了几天代码才摸清十几个表之间的关联那时候我就在想这种重复劳动为什么不能让工具自动做后来我在IDEA里接入了Screw一个开源的数据库文档生成工具实测下来一个几十张表的库一键生成HTML格式的数据库设计文档速度以秒计而且内容永远和数据源同步。这篇文章就把我整理过的一套IDEA下使用Screw的方案完整讲一讲包括环境准备、依赖配置、代码示例还有我这一路踩过的坑。如果你手里有个小项目想快速出文档或者团队需要一份能跟表结构保持一致的数据库说明这篇文章都适合你。哪怕你只装了IDEA社区版也完全不耽误。下面我直接按实操顺序来聊。1. 为什么数据库文档要交给Screw自动生成1.1 手工维护数据库文档的三宗罪先说手工整理文档这件事。我见过不少团队数据库设计文档全靠开发抽时间写Excel表格一张张建字段一行行敲。问题是这种文档的保质期往往不超过两周。第一宗罪是时间成本高。正常一个几十张表的系统手工梳理一遍少说两三个小时。中间还得连着数据库每个表去DESC一下确认字段类型、长度、默认值碰到没有注释的字段还得去代码里猜业务含义。第二宗罪是准确率低。人眼扫一遍字段漏掉一个注释或写错一个类型都是常态更别提表之间外键关系、索引逻辑这种东西光靠肉眼根本看不全。第三宗罪是版本根本收不住。今天你更新了表结构明天文档还在别人手里没同步最后文档和线上库对不上谁也不敢拿它当依据。这三件事叠加在一起结果就是文档沦为了摆设。我甚至在项目里见过一份数据库设计文档里面还写着早已删除的字段新同事参照着建表差点把字段建重复。手工文档的最大问题不在于“写了多少”而在于“维护不起”。1.2 Screw到底解决了什么问题Screw的思路其实很朴素数据库文档无非是表结构元数据的展示而数据库本身就是这些元数据的源头。与其让人手工抄不如让工具直接读库再按模板渲染成文档。这意味着什么意味着只要数据源配置正确生成的文档一定和库表结构一致。表加了字段重新生成一次文档就更新了字段改了注释重新生成一次文档也跟着变。这个“永远同步”的特性恰恰是手工文档最缺的。另外Screw的格式支持也很实用。它可以输出HTML、Word、Markdown三种文件我后面会重点推荐其中一种。它还支持按表名、前缀去忽略某些表比如框架自动生成的flyway_schema_history这种表完全可以不让它出现在文档里。它本身是一个开源的Java工具库MIT协议引入成本低不侵入业务代码放在一个独立模块里随时可以抽走。1.3 四种常见数据库文档方案的对比为了说清楚Screw的选择理由我把自己用过的方案放在一起对比了下。手工Excel/Word是最常见的“土办法”Navicat和DataGrip这类客户端有导出功能专业的PDM建模工具也有文档能力Screw属于自动化脚本型方案。对比维度手工文档Navicat/DataGrip导出PDM建模工具Screw同步实时性完全靠人工手动刷新导出需模型同步生成的文档始终来自当前数据源操作成本极高中等高需要维护模型一次配置后续一条命令字段注释还原容易漏部分支持依赖模型质量依赖建表注释注释有就有格式丰富度取决于手工一般只支持表格导出图表型HTML、Word、Markdown团队协作文档分散、难统一文件分发需要专门建模工具可进Git、可上CI自动生成对比下来Screw最大的优势是“可重复执行”。只要工程在随时可以重新生成这比任何人工维护的方式都靠谱。2. Screw的工作原理与集成前的准备2.1 环境要求先把环境说清楚。JDK8以上、Maven 3.6、IDEA 2020以后的版本都行社区版也完全够用。数据库方面Screw官方支持MySQL、PostgreSQL、Oracle、SQLServer、MariaDB日常遇到的主流关系型数据库基本全覆盖。这里多说一句IDEA版本对Screw没有特殊要求它不依赖IDEA的插件系统本质上就是在工程里跑一段Java代码。所以哪怕你还在用老版本的IDEA只要Maven能拉依赖、能跑测试类就能用。2.2 一键生成背后的四个步骤Screw工作的过程不复杂拆开看就四步完全不涉及什么高深魔法。第一步通过配置的数据源建立JDBC连接。第二步读取数据库里的元数据包括表名、表注释、字段名、字段类型、是否主键、默认值、索引信息。MySQL下它会去查information_schemaOracle则靠USER_TAB_COLUMNS这类系统视图。第三步把读到的元数据填充进预设的FreeMarker模板。第四步把模板渲染结果输出成HTML、Word或Markdown文件落到你指定的目录。你可以把数据库想象成一个仓库Screw就是拿着货单去做盘点的人。它把每个货架上的货物名称、编号、数量全部记录下来再按固定的表格格式打印出来。整个过程里唯一影响文档质量的就是数据库里的表注释和字段注释有没有写清楚这一点后面我会反复强调。2.3 什么时候适合用Screw结合我自己项目里的经验这几类场景用Screw是最合适的。项目交付阶段客户要求提供数据库设计文档直接生成一份HTML交付格式整齐、内容完整。老项目交接来了一个没接触过的系统几十张表不知道怎么下手先跑一份文档出来等于让表结构替你说话。表结构调整留痕比如要对一批表加字段先生成当前版本的文档改动之后再生成一版两个版本对比就能看出差异。自动化构建把生成文档这个动作挂到CI上每次代码更新后自动出一份新文档团队里所有人都能看到最新版。不过有一点要提醒别拿Screw去连生产环境直接生成。生产库的元数据读取虽然影响不大但为了安全最好连本地或测试库或者用一个只有SELECT权限的只读账号。3. IDEA里三步跑通Screw依赖、配置、代码3.1 第一步搭一个最小的工具工程两种方式二选一。第一种在IDEA里新建一个Spring Boot工程不需要勾选任何Web依赖干干净净的普通工程。第二种如果不想新建项目也可以在一个现有项目的src/test目录里加依赖和测试类不影响业务代码。我个人建议用独立工程因为这样Screw相关的依赖不会污染业务模块后续接CI或者多人共用也方便。pom.xml里需要加的核心依赖如下我以MySQL为例dependency groupIdcn.smallbun.screw/groupId artifactIdscrew-core/artifactId version1.0.5/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependencyscrew-core这个包会把FreeMarker、Velocity等模板依赖自动带进来不需要额外加。如果你用的是PostgreSQL或Oracle把mysql驱动换成对应的驱动包就行。这里有个细节Spring Boot 2.7和3.x的依赖管理里JDBC驱动坐标有差异建议显式声明版本避免引入版本冲突。3.2 第二步数据源配置有个关键参数在application.yml里写上你自己的数据源信息。以MySQL为例spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/order_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseInformationSchematrue username: root password: your_password强烈建议不要用明文密码Spring Boot本身支持环境变量占位写成${DB_PASSWORD}然后在系统环境变量里配置就行。这里我要重点讲一下URL里的useInformationSchematrue这个参数。很多第一次用Screw的人生成的文档里表注释、字段注释全是空的表名倒是都在十有八九就是漏了这个参数。MySQL JDBC默认情况下不会去读取information_schema里的注释信息加上这个参数驱动才会把COMMENT带回来。不夸张地说这个参数决定了你的文档是“只剩骨头”还是“有血有肉”。3.3 第三步用十几行代码生成文档我建议把生成逻辑写在测试类里这样不启动Web服务跑完就结束干净利落。下面这段代码我直接在项目里用过你照着改数据源和文件路径就行。import cn.smallbun.screw.core.Configuration; import cn.smallbun.screw.core.engine.EngineConfig; import cn.smallbun.screw.core.engine.EngineFileType; import cn.smallbun.screw.core.engine.EngineTemplateType; import cn.smallbun.screw.core.execute.DocumentationExecute; import cn.smallbun.screw.core.process.ProcessConfig; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import javax.sql.DataSource; import java.util.ArrayList; import java.util.List; SpringBootTest class DbDocGenerateTest { Autowired ApplicationContext applicationContext; Test void documentGenerate() { DataSource dataSource applicationContext.getBean(DataSource.class); EngineConfig engineConfig EngineConfig.builder() .fileOutputDir(System.getProperty(user.dir) /docs) .openOutputDir(false) .fileType(EngineFileType.HTML) .produceType(EngineTemplateType.freemarker) .build(); ListString ignoreTableName new ArrayList(); ignoreTableName.add(flyway_schema_history); ListString ignorePrefix new ArrayList(); ignorePrefix.add(t_); ProcessConfig processConfig ProcessConfig.builder() .ignoreTableName(ignoreTableName) .ignorePrefix(ignorePrefix) .build(); Configuration config Configuration.builder() .version(1.0.0) .description(订单系统数据库设计文档) .dataSource(dataSource) .engineConfig(engineConfig) .produceConfig(processConfig) .build(); new DocumentationExecute(config).execute(); } }代码里几个关键点拆开说。EngineConfig负责定义文件生成规则。fileType可以用EngineFileType.HTML、EngineFileType.WORD、EngineFileType.MD三种格式。fileOutputDir我建议用System.getProperty(user.dir) /docs这种写法它会输出到当前工程目录下的docs文件夹里避免写死D盘路径导致别人克隆项目后跑不通。produceType用FreeMarker模板就行Screw内置了。ProcessConfig是过滤规则。ignoreTableName按完整表名忽略ignorePrefix按前缀忽略。上面这段代码里我忽略了flyway_schema_history和所有t_开头的表。这个配置可以按你的需求调整。Configuration负责汇总组装。version填版本号description填文档描述这就是文档打开后展示的标题。dataSource直接注入engineConfig和produceConfig分别配置文件和过滤规则。最后new DocumentationExecute(config).execute()这行就是真正执行生成的触发器。跑完这段代码文件就已经落在目录里了。至于我为什么推荐HTML格式原因很简单浏览器直接打开就能看样式渲染最完整传给别人也不需要对方装WordMarkdown适合扔进Git仓库做版本管理Word嘛偶尔会有字体嵌入和乱码问题不是首选。3.4 运行并检查生成产物在IDEA里找到这个测试方法直接右键Run。正常情况下控制台会打印生成路径比如Generate the document to: /your/project/docs/订单系统数据库设计文档.html。打开这个路径用浏览器预览一张张表、一个个字段整整齐齐。整个生成过程的速度拿我手上的一个四十多张表的业务库来说初次生成大概一两秒第二次再跑基本都是秒开。这个性能瓶颈主要在数据库元数据查询和模板渲染和表数量不是线性暴涨的关系。跑完如果没看到文件优先检查两件事第一fileOutputDir目录是否存在不存在时部分版本不会自动创建目录第二Configuration里description是否为空默认文件命名会依赖它。4. 进阶玩法忽略表、多数据源、文档自动化4.1 让文档只展示你想展示的表Screw里和表范围相关的配置一共有四类我列一下它们的作用。配置项作用ignoreTableName按完整表名忽略精确匹配ignorePrefix按表名前缀忽略比如忽略所有sys_开头的表designatedTableName只生成指定表名的表精确匹配designatedPrefix只生成指定前缀的表这四个配置可以组合使用逻辑上忽略优先于指定。实际项目里的典型操作是凡是框架自动创建的表比如flyway_schema_history、qrtz_开头的定时任务表全部加进ignore列表然后指定只导出核心业务表比如只导t_order、t_user、t_pay这些前缀为t_的表。这样文档干净很多新同事看的时候也不会被一堆系统表绕晕。4.2 一个工具项目批量生成多库文档如果你手里有多个系统每个系统的库表结构不同也没必要各写一套工程。一个工程里可以配置多个数据源循环生成多份文档。思路很简单在测试类里通过Autowired注入多个DataSource或者用DataSourceBuilder按需创建然后把每个数据源分别组装成一份Configuration各自指定description和fileOutputName循环执行DocumentationExecute。这样跑一次脚本一个项目的文档和另一个项目的文档就都出来了。需要注意多个数据源如果来自不同厂商驱动一定要分别引入。比如MySQL和PostgreSQL混用两个驱动都不能缺。另外不同数据源的URL参数差异很大MySQL要加useInformationSchematruePostgreSQL则要注意currentSchema这些参数直接影响元数据能否读取正确。4.3 把文档生成挂到自动化流程里这个模块单独拎出来后很自然的下一步就是接CI。我见过一个团队的做法是在Jenkins流水线里增加一个构建步骤专门执行这个Screw工具模块生成完文档后自动归档到文档服务器或推到Git仓库的指定目录。这样做到最后是什么效果每次有人改了表结构、提交了代码流水线跑完最新的数据库文档自动更新。团队里所有人看文档永远不需要问“这是哪个版本的”。文档不再是一份静态文件而是跟着代码一起迭代的资产。不过也要泼一盆冷水不要把Screw生成文档的代码写进业务系统的主流程里。它适合作为一个独立的工具任务存在可以是一个独立的Spring Boot工程可以是Maven插件调用的测试类也可以是定时任务。但绝不建议在用户请求链路里触发文档生成那属于资源浪费。5. 实际踩坑记录Screw常见问题速查表5.1 运行报错Could not find driver这个报错基本就是依赖没引全。Screw本身不包含具体数据库驱动你需要手动添加自己用的驱动依赖。MySQL就是mysql-connector-javaPostgreSQL就是postgresql。检查一下pom里是不是只加了screw-core没有加驱动。还有一种情况是驱动坐标版本太老比如MySQL 8.0的库还引着5.1.x的驱动建议换成8.0.33以上。5.2 生成的文档只有表名没有注释这个问题绝大多数是URL参数导致的。请先在连接串里确认有没有useInformationSchematrue没有就加上。如果加了还是空白检查一下建表语句里到底有没有写COMMENT。一个残酷的事实是很多历史表在建表时根本没写注释这种表无论用什么工具都生成不出注释来数据源头就没有。这种情况只能去业务侧补COMMENT或者通过字段命名去猜业务含义。我发现当那些表还没注释时Screw至少能帮你定位出它们提示你要不要补文档这已经比手工翻库强了。5.3 生成的文件中文乱码中文乱码通常分两个层次。第一个层次是Java文件本身编码不对IDEA里一定要保证项目编码是UTF-8设置路径在Settings - Editor - File Encodings。第二个层次是模板渲染输出时编码不对screw的模板默认UTF-8一般不会出问题。真的遇到Word格式乱码我的建议是直接改用HTML或Markdown格式省心很多。HTML在浏览器里打开没有编码困扰Markdown在IDEA里预览同样如此。5.4 提示内嵌端口被占用如果你的Screw工具工程不小心勾选了Spring Web依赖跑起来时会启动内嵌Tomcat占8080端口于是出现端口被占用的报错。其实生成文档根本不需要启动Web服务。解决办法是不要引入spring-boot-starter-web或者把测试类单独放在test目录用SpringBootTest跑它默认不会启动真实Web服务器。如果你已经引入了Web依赖也可以在application.yml里把spring.main.web-application-type设为none强行关闭Web环境。5.5 配置了忽略表但是表还是出现在文档里这个坑我也踩过先检查类名是否拼错。Screw的配置类是ProcessConfig里面的方法是ignoreTableName和ignorePrefix没有“ignoreTable”这种写法拼错了就是编译期报错或者压根不生效。其次MySQL表名在Linux下区分大小写而你配置的忽略名称可能是全小写或全大写导致匹配不上。解决方法是把忽略表名统一成库里的实际大小写。另外如果你设置了designatedPrefix又同时设置了ignorePrefix要注意过滤优先级别让两个规则互相打架。5.6 一点额外的细节心得最后补几个零碎但实用的点。第一数据库的注释质量直接决定文档质量。Screw只是个搬运工库里的COMMENT写得越好文档越专业。所以真正要养成的好习惯不是“写好文档”而是“给表、字段写清楚注释”。第二生成后的文件无论是什么格式都建议放到一个稳定共享的目录比如内部的Wiki附件区或者Git仓库的docs文件夹不然文档生成得再快团队没人看也白搭。第三配置文件里的密码建议用环境变量注入别把数据库口令一起提交到代码仓库里这个习惯不用我多解释。我个人的习惯是每次调整表结构后随手执行一次文档生成然后提交到仓库里和代码变更一起走评审。这份文档永远不用刻意维护但它永远是最新的。把麻烦的、重复的、容易出错的事交给工具把判断和设计留在自己手上这才是用Screw这一类工具最大的价值。
返回列表