liquibase兼容达梦(DM8)问题记录

liquibase是一款很优秀的开源数据库版本管理工具,他可以帮助开发者处理产品各版本间数据库结构及数据的差异,形成数据库版本差异,这样即可在不同的版本间执行migrate。

而随着国际形势的变化, 我们的需求也在逐渐向国产数据库转型,但测试发现,liquibase不支持达梦。于是我们尝试修改liquibase的源码进行适配性兼容。

使liquibase兼容达梦的思路很简单,因达梦描述自己属于Oracle Like数据库,大量语法结构与Oracle近似,故我们以liquibase的OracleDatabase类作为父类,在其基础上进行扩展。说的更详细一点,无非是让liquibase认为我们使用的是Oracle即可,然后再尝试修正一些具体的数据库差异就好。

所以,我们创建DM8Database,继承OracleDatabase类,同时尝试覆写getShortName、getDefaultDatabaseProductName、isCorrectDatabaseImplementation、getDefaultDriver等方法,示例代码如下:

@Override
public String getShortName() {
return PRODUCT_SHORT_NAME;
}

@Override
protected String getDefaultDatabaseProductName() {
return getDatabaseProductName();
}

@Override
public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
return PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName());
}

@Override
public String getDefaultDriver(String url) {
if (url.startsWith(DRIVER_CONN_PERFIX)) {
return DRIVER_STRING;
}
return null;
}

@Override
public Integer getDefaultPort() {
return 5236;
}

当覆写完成后,我们执行,发现报错:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘liquibase’ defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is liquibase.exception.MigrationFailedException: Migration failed for change set classpath:db/tabledefine/t_tf_apiinfo.xml::t_tf_apiinfo-1.0.0::zhangjian:
Reason:
classpath:/db/changelog.xml : liquibase.precondition.core.TableExistsPrecondition@fe7b6b0 : 第1 行附
近出现错误:
无效的表或视图名[ALL_REGISTERED_MVIEWS]

查阅资料发现Oracle中雾化视图存储于ALL_REGISTERED_MVIEWS中,而达梦中并不存在此表。于是修改liquibase源码,去除此针对此表的依赖;我跟踪代码到JdbcDatabaseSnapshot,fastFetchQuery方法,其中有调用queryOracle方法,我们覆写一个queryDameng方法,同时增加判断入口条件,当数据库为达梦时,执行queryDameng方法;

if (database instanceof DM8Database) {
return queryDameng(catalogAndSchema, view);
}

修改后,初始化没有问题了,但是当初始化完成后,再执行,却有在报空指针异常。

此问题的排查颇废了一番功夫,最后发现,问题出在DBA_TAB_COLS表的HIDDEN_COLUMN字段。在达梦数据库(DM8)中,此字段的默认值为NULL,而在Oracle中,此字段为NO。于是我们增加queryDameng方法,去除对HIDDEN_COLUMN字段的限制。

解决完此问题,基本的正常使用没问题了,但是达梦数据库(DM8)本身还存在大量的保留字,例如“context”也是保留字之一,于是我们覆写mustQuoteObjectName方法,按照达梦文档中提供的保留字进行处理,这样liquibase会自动对保留字进行引号处理。

至此,问题全部修正。最终修改后的包,见附件