微操征霸
351.42M · 2026-02-04
“卡脖子”风险倒闭技术自主
“自主可控”成为国家战略
数据作为核心生产要素的地位提升
合规性压力增大
技术成熟度提升
国产技术从可用到好用
信创产业生态的构建
降低供应链风险
长期成本优势
以文件的方式,配合代码仓库进行统一管理。脚本包括:创建表、创建视图、初始化数据、存储过程(已废弃)、新增列等。
示例目录结果入下:
DDL
├─v1.0
├─table_{table_name}_create.sql
├─table_{table_name}_init_data.sql
├─sequence_{sequence_name}.sql
└─view_{view_name}_create.sql
├─v1.1
├─table_{table_name}_create.sql
├─table_{table_name}_add_column.sql
├─sequence_{sequence_name}.sql
└─view_{view_name}_change.sql
├─v1.2
├─table_{table_name}_create.sql
├─table_{table_name}_add_column.sql
├─sequence_{sequence_name}.sql
└─view_{view_name}_create.sql
├─DDL
├─tidb
├─v1.0
└─v1.1
├─dm
├─v1.0
└─v1.1
├─gaussdb
├─v1.0
└─v1.1
├─kingbase
├─v1.0
└─v1.1
大量的重复的工作:建一张表需要写多个数据库的脚本,增加列字段需要修改多个数据库下的脚本。改动需手动在数据库中验证。重复且分散的操作极易出错:给gaussDB修改了,忘记同步处理金仓数据库。进而为线上增加隐患。 多数据库适配进一步的解决方案
解耦数据表的定义与具体DDL实现,并实现工程化。
1.创建不同数据库的 beetl 模板。 2.java程序自动化(可集成至spring boot项目) 3.未来的扩展仅需添加对应数据库的 beetl 模板即可。
├─libs
│ antlr4-runtime-4.9.3.jar
│ beetl-3.20.1.RELEASE.jar
│ beetl-core-3.20.1.RELEASE.jar
│ beetl-default-antlr4.9-support-3.20.1.RELEASE.jar
│ beetl-ext-3.20.1.RELEASE.jar
├─domain
│ ColumnBuilder.java
│ ColumnDefinition.java
│ TableBuilder.java
│ TypeEnum.java
│ DefaultEnum.java
│ TableDefinition.java
│ Main.java
*Builder.java 类为构建对象的build模式。按照个人习惯构建,代码较长,就不展示啦。
其他代码如下:
TableDefinition.java
public class TableDefinition {
private String database;
private String tableName;
private String comment;
private String tablespace;
private List<ColumnDefinition> columns;
}
ColumnDefinition.java
public class ColumnDefinition {
private String name;
private TypeEnum type;
private int length;
private int precision;
private int scale;
private String comment;
private DefaultEnum defaultValueEnum = DefaultEnum.NONE;
private String defaultValue;
}
TypeEnum.java
public enum TypeEnum {
STRING,
NUMBER,
CLOB,
DATE
}
DefaultEnum.java
public enum DefaultEnum {
CURRENT_DATE, // 当前时间
SYS_ID, // 数据库ID
NONE, // 无默认值
FIX_VALUE // 指定默认值
}
Main.java
public class Main {
public static void main(String[] args){
new Main().check();
}
public void check() {
TableDefinition poc_project_baseinfo = TableDefinition.builder()
.name("test_table")
.database("test_user")
.comment("测试表")
.column(ColumnDefinition.builder()
.string()
.name("id")
.length(50)
.comment("ID")
.build())
.column(ColumnDefinition.builder()
.string()
.name("project_name")
.comment("名称").build())
.build();
List<TableDefinition> tables = Arrays.asList(poc_project_baseinfo);
// 篇幅限制,自动化部分下次分享
GroupTemplate gt1 = getGroupTemplate("gaussdb");
Template t1 = gt1.getTemplate("beetl/base/create_table.btl");
t1.binding("tables", tables);
String r1 = t1.render();
// 仅打印 create table ddl
System.out.println(r1);
GroupTemplate gt2 = getGroupTemplate("dm");
Template t2 = gt.getTemplate("beetl/base/create_table.btl");
t2.binding("tables", tables);
String r2 = t2.render();
// 仅打印 create table ddl
System.out.println(r2);
}
public GroupTemplate getGroupTemplate(String database) {
try {
ClasspathResourceLoader loader = new ClasspathResourceLoader();
Configuration conf = Configuration.defaultConfiguration();
System.out.println(conf.getTagMap());
GroupTemplate gt = new GroupTemplate(loader, conf);
Map<String, Object> shareVars = new HashMap<>();
shareVars.put("StringEnum", TypeEnum.STRING);
shareVars.put("NumberEnum", TypeEnum.NUMBER);
shareVars.put("ClobEnum", TypeEnum.CLOB);
shareVars.put("DateEnum", TypeEnum.DATE);
shareVars.put("CURRENT_DATE", DefaultEnum.CURRENT_DATE);
shareVars.put("SYS_ID", DefaultEnum.SYS_ID);
shareVars.put("NONE", DefaultEnum.NONE);
shareVars.put("FIX_VALUE", DefaultEnum.FIX_VALUE);
shareVars.put("database", database);
gt.setSharedVars(shareVars);
return gt;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
├─beetl
├─base
├─add_column.btl
├─check_ds.btl
├─check_table_column.btl
└─create_table.btl
├─gaussdb
├─check_ds.btl
├─check_table_column.btl
├─create_column.btl
└─tablespace.btl
└─dm
├─check_ds.btl
├─check_table_column.btl
├─create_column.btl
└─tablespace.btl
定义通用脚本格式,将数据库差异部分交由对应数据库下的脚本执行。利用beetl中的 include 标签实现。
base/check_ds.btl 检查基础环境。
可根据基建情况自定义,如数据库名、用户名、对应的tablespace是否存在等等。
# 使用include标签将由对应数据库实现
<% include("../" + database + "/check_ds.btl"){} %>
base/check_table_column.btl 检查表和列是否已经存在
# 使用include标签将由对应数据库实现
<% include("../" + database + "/check_table_column.btl"){} %>
base/create_table.btl 基础建表语句
<%
for(table in tables) {
%>
create table ${table.database}.${table.tableName} (
<%
for(column in table.columns) {
var end ="";
if(!columnLP.last){
end = ",";
}
# 列信息差异交由各自数据库的 create_column.btl 模板实现
include("../" + database + "/create_column.btl",{column:column,end:end}){}
}
%>
) <% include("../" + database + "/tablespace.btl",{table:table}){} %>;
COMMENT ON TABLE ${table.database}.${table.tableName} IS '${table.comment}';
<%
for(column in table.columns) {
%>
COMMENT ON COLUMN ${table.database}.${table.tableName}.${column.name} IS '${column.comment}';
<%
}
%>
<%
}
%>
gaussdb/check_ds.btl
SELECT user FROM dual;test_user;check failed. user must be test_user
select spcname from pg_tablespace where spcname='test_user_ts';test_user_ts;check failed. cannot find tablespace test_user_ts
gaussdb/check_table_column.btl
select table_name,column_name from information_schema.columns where table_schema='test_user' and table_name in (
<% for(table in tables) { %>
'${table.tableName}'<% if(!tableLP.last) {%>,<% } %>
<% } %>
)
gaussdb/create_column.btl
<% if(column.type == StringEnum ){ %>
${column.name} VARCHAR2(${column.length}) <% if(column.defaultValueEnum == FIX_VALUE){ %>default '${column.defaultValue}'<% } %> <% if(column.defaultValueEnum == SYS_ID){ %>default sys_guid()<% } %> ${end}
<% } else if (column.type == NumberEnum) { %>
${column.name} NUMBER(${column.precision},${column.scale}) <% if(column.defaultValueEnum == FIX_VALUE){ %>default ${column.defaultValue}<% } %> ${end}
<% } else if (column.type == ClobEnum) { %>
${column.name} CLOB ${end}
<% } else if (column.type == DateEnum) { %>
${column.name} DATE <% if(column.defaultValueEnum == CURRENT_DATE){ %>default sysdate<% } %> ${end}
<% } %>
gaussdb/tablespace.btl
tablespace ${table.tablespace}