数据库方言配置特殊机制
数据库方言高级配置
本文档详细介绍数据库方言配置的高级配置,包括继承机制、数据类型映射过程和建表语句模板详解。
继承机制与配置复用
数据库方言配置的一个重要特性是继承机制,它允许新的数据库方言配置继承已有方言的配置,大大减少了配置工作量。继承机制的工作原理如下:
在
hetu.toml的[extend]部分定义继承关系,例如:[extend] polardb = { type = "postgresql" }这表示
polardb继承postgresql的所有配置。系统首先加载
hetu.toml中的基础配置,包括通用数据类型、函数和模板。然后加载被继承的数据库配置文件(如
postgresql.toml)。最后加载当前数据库的配置文件(如
polardb.toml),它可以覆盖前面的配置。
配置优先级
配置的优先级从高到低为:
- 特定数据库配置文件(如
polardb.toml) - 被继承的数据库配置文件(如
postgresql.toml) hetu.toml中的基础配置
继承的优势
利用继承机制的主要优势:
减少重复配置:如果新数据库与现有数据库非常相似(如PolarDB与PostgreSQL),则只需配置不同的部分。
简化维护:当基础配置或被继承的配置更新时,所有继承它的配置自动获得更新。
增强一致性:确保相似数据库之间的配置保持一致。
实际应用示例
例如,如果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配置自动生成的。整个映射过程如下:
从模型定义获取JDBC类型: 系统首先从模型定义或字段定义中获取JDBC类型(如VARCHAR、INTEGER等)和长度、精度、小数位等参数。
查找对应的type.XXX配置: 系统查找数据库方言配置中对应的
type.XXX配置节。例如,对于VARCHAR类型,系统会查找type.VARCHAR配置。应用expr模板和参数: 系统将字段的长度、精度等参数应用到
expr模板中。例如,对于长度为50的VARCHAR字段:[type.VARCHAR] expr = "VARCHAR({length})" # 模板系统将
{length}替换为"50",生成"VARCHAR(50)"作为最终的dataType值。范围验证: 系统会验证参数值是否在配置的范围内。例如,对于VARCHAR类型,长度必须在
min和max之间:[type.VARCHAR] length = { min = 0, max = 65535 } # 验证长度范围应用到建表模板: 生成的类型字符串(如
"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类型
...
}
]
}系统处理过程:
对于
id字段:- 查找
type.INTEGER配置 - 应用
expr模板:"INTEGER" - 最终
dataType值为:"INTEGER"
- 查找
对于
username字段:- 查找
type.VARCHAR配置 - 验证长度50是否在范围内(0-65535)
- 应用
expr模板并替换{length}:"VARCHAR(50)" - 最终
dataType值为:"VARCHAR(50)"
- 查找
对于
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})
);
>>
"""模板函数定义:
create(columns, tableName, pk, tableComment) ::= <<...>>:定义了一个名为create的模板函数,接受四个参数:columns:表的列定义数组tableName:表名pk:主键列名tableComment:表注释
SQL语句生成:
CREATE TABLE {tableName} (...):生成基本的建表语句,其中{tableName}会被替换为实际的表名
列定义循环:
{columns:{c |...}; separator=",\n"}:这是一个循环,遍历columns数组中的每个元素c,为每个列生成定义,并用逗号和换行符分隔
列定义格式:
{c.columnName} {c.dataType}:列名和数据类型{if(c.defaultValue)} {c.defaultExpr} {c.defaultValue}{endif}:条件判断,如果有默认值,则添加默认值表达式和默认值{if(!c.nullable)} {c.nullableExpr}{endif}:条件判断,如果列不可为空,则添加非空约束
主键定义:
PRIMARY KEY ({pk}):定义表的主键
参数详解
columns(数组):表的列定义,每个元素是一个包含以下属性的对象:columnName:列名dataType:数据类型,如"VARCHAR(100)"defaultValue:默认值(可选)defaultExpr:默认值表达式,通常为"DEFAULT"(当有默认值时使用)nullable:是否可为空(布尔值)nullableExpr:非空约束表达式,通常为"NOT NULL"(当不可为空时使用)
tableName(字符串):表的名称pk(字符串):主键列名或多个主键列名的组合tableComment(字符串):表的注释或描述
通过这种方式,系统可以为不同的数据库生成符合其语法要求的SQL语句,而业务代码无需关心这些差异。
