JVS低代码动态建表原理:从模型配置到数据库DDL的生成逻辑

摘要区:

JVS低代码的数据模型引擎无需手动建表,通过可视化配置自动生成数据库表结构。本文从源码层面解析其实现:模型配置JSON如何转换为DDL语句,如何处理字段类型映射、索引、外键,以及版本升级时的增量变更策略。


一、问题的提出

传统开发中,每新增一个业务模块,都需要手动编写CREATE TABLE、ALTER TABLE等DDL语句,并与实体类保持同步。JVS低代码的数据模型引擎实现了"配置即表结构"的能力,其核心挑战在于:

  • 如何将用户拖拽配置的字段(文本、数字、日期、选项等)映射为MySQL/PostgreSQL等数据库的数据类型?

  • 如何保证模型修改后,存量数据不丢失?

  • 如何处理字段重命名、删除等破坏性操作?

本文将以JVS低代码v2.5源码为基础,分步骤解析动态建表的完整逻辑。

二、整体流程概览

用户在前端配置数据模型 → 保存模型JSON → 后端解析 → 生成Diff变更计划 → 执行DDL → 更新模型版本号。

核心类位于 jvs-modules/data-model 模块:

text

复制代码
com.jvs.dm.service.ModelDDLService
├── generateCreateDDL()      // 新建模型时生成CREATE TABLE
├── generateAlterDDL()       // 修改模型时生成ALTER TABLE
├── columnTypeMapping()      // 类型映射
└── executeWithVersion()     // 执行DDL并记录版本
三、关键源码解析

3.1 字段类型映射规则

JVS定义了一套抽象数据类型(JvsFieldType),然后根据数据库方言转换:

java

复制代码
public enum JvsFieldType {
    TEXT,      // 短文本 → VARCHAR(255)
    LONG_TEXT, // 长文本 → TEXT
    NUMBER,    // 数字 → DECIMAL(20,4)
    INTEGER,   // 整数 → BIGINT
    DATE,      // 日期 → DATE
    DATETIME,  // 日期时间 → DATETIME(3)
    BOOLEAN,   // 布尔 → TINYINT(1)
    OPTION,    // 选项 → VARCHAR(100)
    FILE,      // 附件 → VARCHAR(500) 存储路径
    REFERENCE; // 关联 → BIGINT 存储关联ID
}

转换核心代码(简化版):

java

复制代码
public String toColumnDefinition(JvsField field, Dialect dialect) {
    String type = field.getType().getSqlType(dialect);
    StringBuilder sb = new StringBuilder();
    sb.append(field.getName()).append(" ").append(type);
    if (field.isRequired()) sb.append(" NOT NULL");
    if (field.getDefaultValue() != null) sb.append(" DEFAULT '").append(field.getDefaultValue()).append("'");
    return sb.toString();
}

3.2 Diff算法:模型变更检测

当用户修改模型(新增/修改/删除字段)时,引擎会比较旧模型JSON与新模型JSON,生成变更列表:

java

复制代码
public List<SchemaChange> diff(Model oldModel, Model newModel) {
    List<SchemaChange> changes = new ArrayList<>();
    // 新增字段
    for (Field newField : newModel.getFields()) {
        if (oldModel.getField(newField.getName()) == null) {
            changes.add(new AddColumnChange(newField));
        }
    }
    // 删除字段:将字段标记为deleted(不实际删除列,避免数据丢失)
    for (Field oldField : oldModel.getFields()) {
        if (newModel.getField(oldField.getName()) == null) {
            changes.add(new SoftDeleteColumnChange(oldField));
        }
    }
    // 修改字段(类型、长度、是否必填)
    // ... 使用比较器
    return changes;
}

实际执行DDL时,对删除字段的处理

  • 不执行 DROP COLUMN,而是重命名为 {field_name}_deleted_{timestamp},并记录到 deleted_columns 元数据表中。

  • 这样既避免了数据丢失,又允许用户随时恢复。

3.3 版本控制与回滚

每次执行DDL后,系统会在 jvs_model_version 表中记录:

字段 说明
model_id 模型ID
version 版本号(自增)
ddl_sql 执行的DDL语句
schema_snapshot 完整表结构的JSON快照
created_at 执行时间

用户可通过管理后台回滚到任意历史版本,系统会根据 schema_snapshot 反向生成回滚DDL。

四、扩展实践:自定义字段类型

如果默认类型不满足需求(如需要GIS地理类型),可通过插件机制注册:

  1. 实现 CustomTypeHandler 接口。

  2. resources/META-INF/services/com.jvs.dm.CustomTypeHandler 中注册。

  3. 前端组件库中增加对应的编辑器。

示例:注册PostgreSQL的 GEOMETRY 类型:

java

复制代码
public class GeometryTypeHandler implements CustomTypeHandler {
    @Override
    public String getTypeName() { return "GEOMETRY"; }
    @Override
    public String toSqlType(Dialect dialect) {
        return "GEOMETRY";
    }
}
五、总结

JVS低代码的动态建表引擎通过模型驱动DDL生成、非破坏性变更检测、版本快照回滚等设计,实现了生产环境可靠的零代码表结构管理。开发者可直接复用此机制,或二次开发自定义字段类型。

相关推荐
AI-好学者7 小时前
阶段一-图数据库基础与PropertyGraph模型
数据库·rag·knowledge graph·graphrag
快乐非自愿8 小时前
AI低代码破局:数字化降本增效的核心逻辑与商业落地
人工智能·低代码
其实防守也摸鱼9 小时前
运维--学习阶段问题解答(1)(自测)
linux·运维·服务器·数据库·学习·自动化·命令模式
懒鸟一枚9 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
龙仔7259 小时前
SQL Server 创建只读账号完整操作(分两种场景:SSMS图形界面 + T-SQL脚本)
数据库·sql·oracle
霁月的小屋9 小时前
生产环境中的事务实践——银行系统上线记(四)
数据库
Database_Cool_10 小时前
AI 应用数据底座首选:阿里云 PolarDB 为大模型 RAG 提供一体化支撑
数据库·阿里云
玖玥拾10 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
IvorySQL11 小时前
PG 日报|社区讨论重构 pg_hba 配置文件格式
数据库·人工智能·postgresql·重构·ivorysql
逝水无殇11 小时前
C# 文件的输入与输出详解
开发语言·数据库·后端·c#