跳至主要內容

数据库方言配置特殊机制

2025年7月7日大约 5 分钟

数据库方言高级配置

本文档详细介绍数据库方言配置的高级配置,包括继承机制、数据类型映射过程和建表语句模板详解。

继承机制与配置复用

数据库方言配置的一个重要特性是继承机制,它允许新的数据库方言配置继承已有方言的配置,大大减少了配置工作量。继承机制的工作原理如下:

  1. 在hetu.toml的[extend]部分定义继承关系,例如:

    [extend]
    polardb = { type = "postgresql" }

    这表示polardb继承postgresql的所有配置。

  2. 系统首先加载hetu.toml中的基础配置,包括通用数据类型、函数和模板。

  3. 然后加载被继承的数据库配置文件(如postgresql.toml)。

  4. 最后加载当前数据库的配置文件(如polardb.toml),它可以覆盖前面的配置。

配置优先级

配置的优先级从高到低为:

  1. 特定数据库配置文件(如polardb.toml)
  2. 被继承的数据库配置文件(如postgresql.toml)
  3. hetu.toml中的基础配置

继承的优势

利用继承机制的主要优势:

  1. 减少重复配置:如果新数据库与现有数据库非常相似(如PolarDB与PostgreSQL),则只需配置不同的部分。

  2. 简化维护:当基础配置或被继承的配置更新时,所有继承它的配置自动获得更新。

  3. 增强一致性:确保相似数据库之间的配置保持一致。

实际应用示例

例如,如果PolarDB基本兼容PostgreSQL,那么在polardb.toml中只需定义特定的差异部分:

# polardb.toml - 只需定义与PostgreSQL不同的部分

[jdbc]
driverClass = "com.polardb.jdbc.Driver"
urlPrefix = "jdbc:polardb"
url = "jdbc:polardb://{host}:{port}/{databaseName}"

# 其他特定配置...

系统会自动从PostgreSQL配置中继承其他未定义的配置项,如数据类型映射、元数据查询SQL和SQL模板等。而PostgreSQL又会从hetu.toml中继承通用配置。

提示

当添加新的数据库方言时,如果它与现有数据库高度兼容,强烈建议使用继承机制。只需在hetu.toml的[extend]部分配置继承关系,然后在特定的配置文件中只定义差异部分,可以大大减少配置工作量和出错可能性。

数据类型映射详解

建表模板中的dataType字段值是由系统根据type.XXX配置自动生成的。整个映射过程如下:

  1. 从模型定义获取JDBC类型: 系统首先从模型定义或字段定义中获取JDBC类型(如VARCHAR、INTEGER等)和长度、精度、小数位等参数。

  2. 查找对应的type.XXX配置: 系统查找数据库方言配置中对应的type.XXX配置节。例如,对于VARCHAR类型,系统会查找type.VARCHAR配置。

  3. 应用expr模板和参数: 系统将字段的长度、精度等参数应用到expr模板中。例如,对于长度为50的VARCHAR字段:

    [type.VARCHAR]
    expr = "VARCHAR({length})"  # 模板

    系统将{length}替换为"50",生成"VARCHAR(50)"作为最终的dataType值。

  4. 范围验证: 系统会验证参数值是否在配置的范围内。例如,对于VARCHAR类型,长度必须在min和max之间:

    [type.VARCHAR]
    length = { min = 0, max = 65535 }  # 验证长度范围
  5. 应用到建表模板: 生成的类型字符串(如"VARCHAR(50)")作为dataType值,应用到建表模板中。

映射示例

假设我们有以下类型配置:

[type.VARCHAR]
expr = "VARCHAR({length})"
length = { min = 0, max = 65535 }

[type.INTEGER]
expr = "INTEGER"

[type.TIMESTAMP]
expr = "TIMESTAMP"

当我们定义表结构时(简化表示):

{
  columns: [
    {
      name: "id",
      type: "INTEGER",  // JDBC类型
      ...
    },
    {
      name: "username",
      type: "VARCHAR",  // JDBC类型
      length: 50,       // 长度参数
      ...
    },
    {
      name: "created_at",
      type: "TIMESTAMP", // JDBC类型
      ...
    }
  ]
}

系统处理过程:

  1. 对于id字段:

    • 查找type.INTEGER配置
    • 应用expr模板:"INTEGER"
    • 最终dataType值为:"INTEGER"
  2. 对于username字段:

    • 查找type.VARCHAR配置
    • 验证长度50是否在范围内(0-65535)
    • 应用expr模板并替换{length}:"VARCHAR(50)"
    • 最终dataType值为:"VARCHAR(50)"
  3. 对于created_at字段:

    • 查找type.TIMESTAMP配置
    • 应用expr模板:"TIMESTAMP"
    • 最终dataType值为:"TIMESTAMP"

然后,这些生成的dataType值被应用到建表模板中,生成最终的SQL语句:

CREATE TABLE users (
  id INTEGER NOT NULL,
  username VARCHAR(50) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

这种设计使得应用代码可以使用统一的JDBC类型,而系统会根据目标数据库自动生成适合的SQL数据类型。

建表语句模板详解

建表语句模板(createTable)使用StringTemplate引擎的语法,用于生成创建表的SQL语句。这个模板定义了如何将表的元数据(列定义、主键等)转换为特定数据库方言的建表SQL语句。

模板语法解析

createTable = """
create(columns, tableName, pk, tableComment) ::= <<
CREATE TABLE {tableName} (
{columns:{c |{c.columnName} {c.dataType}{if(c.defaultValue)} {c.defaultExpr} {c.defaultValue}{endif}{if(!c.nullable)} {c.nullableExpr}{endif}}; separator=",
"},
PRIMARY KEY ({pk})
);
>>
"""
  1. 模板函数定义:

    • create(columns, tableName, pk, tableComment) ::= <<...>>:定义了一个名为create的模板函数,接受四个参数:
      • columns:表的列定义数组
      • tableName:表名
      • pk:主键列名
      • tableComment:表注释
  2. SQL语句生成:

    • CREATE TABLE {tableName} (...):生成基本的建表语句,其中{tableName}会被替换为实际的表名
  3. 列定义循环:

    • {columns:{c |...}; separator=",\n"}:这是一个循环,遍历columns数组中的每个元素c,为每个列生成定义,并用逗号和换行符分隔
  4. 列定义格式:

    • {c.columnName} {c.dataType}:列名和数据类型
    • {if(c.defaultValue)} {c.defaultExpr} {c.defaultValue}{endif}:条件判断,如果有默认值,则添加默认值表达式和默认值
    • {if(!c.nullable)} {c.nullableExpr}{endif}:条件判断,如果列不可为空,则添加非空约束
  5. 主键定义:

    • PRIMARY KEY ({pk}):定义表的主键

参数详解

  1. columns(数组):表的列定义,每个元素是一个包含以下属性的对象:

    • columnName:列名
    • dataType:数据类型,如"VARCHAR(100)"
    • defaultValue:默认值(可选)
    • defaultExpr:默认值表达式,通常为"DEFAULT"(当有默认值时使用)
    • nullable:是否可为空(布尔值)
    • nullableExpr:非空约束表达式,通常为"NOT NULL"(当不可为空时使用)
  2. tableName(字符串):表的名称

  3. pk(字符串):主键列名或多个主键列名的组合

  4. tableComment(字符串):表的注释或描述

通过这种方式,系统可以为不同的数据库生成符合其语法要求的SQL语句,而业务代码无需关心这些差异。

上次编辑于: 2025/7/7 17:37:43
贡献者: zhangshuaic