序言
最近公司里有一个新的需求,需要导出数据库元数据表中存储的表的 ddl 语句,而在元数据表中数据源的类型庞大,少则十几种多则达到几十种,各种数据库类型都有,比如常见就有 mysql postgresql oracle sql server等等,而不同的数据库其数据类型和语法都存在一些差异,如果在代码中去处理工作量就太大了。所以我想到使用模版引擎来处理,现在市面上出现了一个新的模版引擎 beetl。本篇文章就从这个模版引擎来入手介绍如何实现功能。代码已经提交到了我的 github 仓库
beetl
beetl 的使用方式和 thymeleaf、freemarker 差不多,而且其语法简单,性能也优于这两者,目前在国内已经有一定的用户群体。话不多说,具体的使用方式非常简单,大家看一下官网就会了,下面来说功能怎么实现
代码
使用前在springboot中使用的时候需要先导入依赖,我测试的 springboot 的版本为 3.2.1
<dependency>
<groupid>com.ibeetl</groupid>
<artifactid>beetl-spring-boot-starter-classic</artifactid>
<version>3.19.1.release</version>
</dependency>
创建一下库表,因为模版文件是存储在数据库中,方便后期维护
create table ddl_template
(
id int auto_increment
primary key,
name varchar(255) not null,
description varchar(255) null,
created_at timestamp not null,
updated_at timestamp null,
created_by varchar(255) null,
updated_by varchar(255) null,
version float not null,
db_type varchar(255) not null,
template text not null
)
comment 'ddl模板表' charset = utf8mb4;
表创建完成后,我事先往这个表中添加了三条数据,分别代表 mysql、oracle、pgsql 的ddl 模版

mysql:
drop table if exists `${table.tablecode}`;
create table ${table.tablecode}(
<%
for(field in fieldlist){
var code = field.code;
var comment = field.comment;
var type = field.type;
var len = field.len;
var scale = field.scale;
var notnull = field.notnull;
var autoincrement = field.autoincrement;
var defaultvalue = field.defaultvalue;
var last = fieldlp.last;
if (len != null) {
if (len > 0) {
var temp = "(" + len;
if (scale != null) {
if (scale > 0) {
temp = temp + "," + scale;
}
}
temp = temp + ")";
type = type + temp;
}
}
%>
`${field.code}` ${type}${autoincrement ? " auto_increment":""}${notnull ? " not null":" null"}${defaultvalue != null ? " default '" + defaultvalue + "'" : "" }
${comment != null ? " comment '" + comment + "'":""}${!last ? ",":""}
<%
}
%>
<%
if (primarykey != null){
%>
,primary key (${primarykey})
<%
}
%>
) comment = '${table.tablecomment}';
oracle:
create table "${table.tablecode}"(
<%
for(field in fieldlist){
var code = field.code;
var comment = field.comment;
var type = field.type;
var len = field.len;
var scale = field.scale;
var primarykey = field.primarykey;
var notnull = field.notnull;
var defaultvalue = field.defaultvalue;
var last = fieldlp.last;
if (len != null && type != 'date') {
if (len > 0) {
var temp = "(" + len;
if (scale != null) {
if (scale > 0) {
temp = temp + "," + scale;
}
}
temp = temp + ")";
type = type + temp;
}
}
if (type == 'date') {
defaultvalue = null;
notnull = false;
}
%>
"${field.code}" ${type}${defaultvalue != null ? " default '" + defaultvalue + "'" : "" }${notnull ? " not null":" null"}${!last ? ",":""}
<%
}
%>
<%
if (primarykey != null){
%>
,primary key ("${primarykey}")
<%
}
%>
);
comment on table "${table.tablecode}" is '${table.tablecomment}';
<%
for(field in fieldlist){
var code = field.code;
var comment = field.comment;
var last = fieldlp.last;
%>
comment on column "${table.tablecode}"."$[code]" is '${comment}';
<%
}
%>
pgsql:
drop table if exists "${table.tablecode}";
create table "${table.tablecode}"(
<%
for(field in fieldlist){
var code = field.code;
var comment = field.comment;
var type = field.type;
var len = field.len;
var scale = field.scale;
var notnull = field.notnull;
var autoincrement = field.autoincrement;
var defaultvalue = field.defaultvalue;
var last = fieldlp.last;
if (len != null) {
if (len > 0) {
var temp = "(" + len;
if (scale != null) {
if (scale > 0) {
temp = temp + "," + scale;
}
}
temp = temp + ")";
type = type + temp;
}
}
%>
"$[code]" ${type}${autoincrement ? " generated always as identity" : ""}${notnull ? " not null" : ""}${defaultvalue != null ? " default '" + defaultvalue + "'" : "" }
${!last ? "," : ""}
<%
}
%>
<%
if (primarykey != null){
%>
,primary key (${primarykey})
<%
}
%>
);
comment on table "${table.tablecode}" is '${table.tablecomment}';
<%
for(field in fieldlist){
var code = field.code;
var comment = field.comment;
if (comment != null) {
%>
comment on column "${table.tablecode}"."$[code]" is '${comment}';
<%
}
}
%>
准备工作完成后,接下来开发代码,具体代码如下:
@bean
public grouptemplate grouptemplate() throws exception {
stringtemplateresourceloader loader = new stringtemplateresourceloader();
org.beetl.core.configuration cfg = org.beetl.core.configuration.defaultconfiguration();
grouptemplate gt = new grouptemplate(loader, cfg);
return gt;
}
这里使用的 stringtemplateresourceloader 表示从字符串中来加载模板,也有其他的 resourceloader,比如 fileresourceloader 表示从文件中加载模版,具体的看官网就可以了
/**
* 单张表的ddl语句创建
*
* @return
*/
@postmapping("/createddl")
public void createddl(@requestparam("version") string version,@requestparam("dbtype") string dbtype) {
ddltemplateservice.createddl(version, dbtype);
}
@override
public void createddl(string version, string dbtype) {
dbenum dbenum = dbenum.fromstring(dbtype);
assert.notnull(dbtype, "数据库类型不支持");
switch (dbenum) {
case mysql:
generatemysqlddl(version, dbtype, buildmysqldata());
break;
case oracle:
generateoracleddl(version, dbtype, buildoracledata());
break;
case postgresql:
generatepostgresqlddl(version, dbtype, buildpostgresqldata());
break;
}
}
这里支持的数据库类型还比较少,大家可以后面扩充
/**
* 这里只是模拟一下,实际情况应该是从数据库中查询的对应的表及字段
*
* @return
*/
private map<string, object> buildmysqldata() {
mysqltable tablevo = mysqltable.builder().tablecode("t_user").tablecomment("用户表").build();
list<mysqlfield> fieldvolist = list.of(
mysqlfield.builder().code("id").comment("主键").type("int").len(11).scale(0.0).autoincrement(true).notnull(true).build(),
mysqlfield.builder().code("name").comment("姓名").type("varchar").len(50).scale(0.0).autoincrement(false).defaultvalue("").notnull(true).build(),
mysqlfield.builder().code("age").comment("年龄").type("int").len(11).scale(0.0).autoincrement(false).notnull(true).build(),
mysqlfield.builder().code("email").comment("邮箱").type("varchar").len(50).scale(0.0).autoincrement(false).defaultvalue("").notnull(true).build(),
mysqlfield.builder().code("create_time").comment("创建时间").type("date").len(0).scale(0.0).autoincrement(false).notnull(true).notnull(true).build()
);
return map.of("table", tablevo, "fieldlist", fieldvolist, "primarykey", "id");
}
private map<string, object> buildoracledata() {
oracletable tablevo = oracletable.builder().tablecode("t_user").tablecomment("用户表").build();
list<oraclefield> fieldvolist = list.of(
oraclefield.builder().code("id").comment("主键").type("number").len(11).scale(0.0).autoincrement(true).notnull(true).build(),
oraclefield.builder().code("name").comment("姓名").type("varchar").len(50).scale(0.0).autoincrement(false).defaultvalue("").notnull(true).build(),
oraclefield.builder().code("age").comment("年龄").type("number").len(11).scale(0.0).autoincrement(false).notnull(true).build(),
oraclefield.builder().code("email").comment("邮箱").type("varchar").len(50).scale(0.0).autoincrement(false).defaultvalue("").notnull(true).build(),
oraclefield.builder().code("create_time").comment("创建时间").type("date").len(0).scale(0.0).autoincrement(false).notnull(true).notnull(true).build()
);
return map.of("table", tablevo, "fieldlist", fieldvolist, "primarykey", "id");
}
private map<string, object> buildpostgresqldata() {
postgresqltable tablevo = postgresqltable.builder().tablecode("t_user").tablecomment("用户表").build();
list<postgresqlfield> fieldvolist = list.of(
postgresqlfield.builder().code("id").comment("主键").type("integer").autoincrement(true).notnull(true).build(),
postgresqlfield.builder().code("name").comment("姓名").type("varchar").len(50).scale(0.0).autoincrement(false).defaultvalue("").notnull(true).build(),
postgresqlfield.builder().code("age").comment("年龄").type("int").autoincrement(false).notnull(true).build(),
postgresqlfield.builder().code("email").comment("邮箱").type("varchar").len(50).scale(0.0).autoincrement(false).defaultvalue("").notnull(true).build(),
postgresqlfield.builder().code("create_time").comment("创建时间").type("timestamp").len(0).scale(0.0).autoincrement(false).notnull(true).notnull(true).build()
);
return map.of("table", tablevo, "fieldlist", fieldvolist, "primarykey", "id");
}
private void generatemysqlddl(string version, string dbtype, map<string, object> data) {
try {
// 可以考虑将模版文件缓存
template template = grouptemplate.gettemplate(querybyunique(version, dbtype).gettemplate());
template.binding(data);
string render = template.render();
log.info("生成mysqlddl语句成功");
fileutil.writeutf8string(render, "d:/ddl.sql");
} catch (exception e) {
throw new runtimeexception("生成ddl语句失败", e);
}
}
private void generateoracleddl(string version, string dbtype, map<string, object> data) {
try {
// 可以考虑将模版文件缓存
template template = grouptemplate.gettemplate(querybyunique(version, dbtype).gettemplate());
template.binding(data);
string render = template.render();
log.info("生成oracleddl语句成功");
fileutil.writeutf8string(render, "d:/ddl.sql");
} catch (exception e) {
throw new runtimeexception("生成ddl语句失败", e);
}
}
private void generatepostgresqlddl(string version, string dbtype, map<string, object> data) {
// 可以考虑将模版文件缓存
template template = grouptemplate.gettemplate(querybyunique(version, dbtype).gettemplate());
template.binding(data);
string render = template.render();
log.info("生成pgsqlddl语句成功");
fileutil.writeutf8string(render, "d:/ddl.sql");
}
我这里运行后会分别针对不同的数据库类型来生成对应的表 ddl 语句,效果如下:
mysql
drop table if exists `t_user`;
create table t_user(
`id` int(11) auto_increment not null
comment '主键',
`name` varchar(50) not null default ''
comment '姓名',
`age` int(11) not null
comment '年龄',
`email` varchar(50) not null default ''
comment '邮箱',
`create_time` date not null
comment '创建时间'
,primary key (id)
) comment = '用户表';
oracle
create table "t_user"(
"id" number(11) not null,
"name" varchar(50) default '' not null,
"age" number(11) not null,
"email" varchar(50) default '' not null,
"create_time" date null
,primary key ("id")
);
comment on table "t_user" is '用户表';
comment on column "t_user"."id" is '主键';
comment on column "t_user"."name" is '姓名';
comment on column "t_user"."age" is '年龄';
comment on column "t_user"."email" is '邮箱';
comment on column "t_user"."create_time" is '创建时间';
pgsql
drop table if exists "t_user";
create table "t_user"(
"id" integer generated always as identity not null
,
"name" varchar(50) not null default ''
,
"age" int not null
,
"email" varchar(50) not null default ''
,
"create_time" timestamp not null
,primary key (id)
);
comment on table "t_user" is '用户表';
comment on column "t_user"."id" is '主键';
comment on column "t_user"."name" is '姓名';
comment on column "t_user"."age" is '年龄';
comment on column "t_user"."email" is '邮箱';
comment on column "t_user"."create_time" is '创建时间';
这三个 ddl 语句在对应的数据库里面是可以运行



总结
这里采用数据库存储模版的方式比在代码中硬编码维护性要好,不然模版有改动的话,还需要去修改代码重新打包,总体下来并不是很难。
以上就是springboot+beetl实现动态数据库ddl的示例代码的详细内容,更多关于springboot beetl动态数据库ddl的资料请关注代码网其它相关文章!
发表评论