摘要区:

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生成、非破坏性变更检测、版本快照回滚等设计,实现了生产环境可靠的零代码表结构管理。开发者可直接复用此机制,或二次开发自定义字段类型。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐