目录

Liquibase-和-Flowable-6-支持人大金仓-KingbaseES-数据库

Liquibase 和 Flowable 6 支持人大金仓 (KingbaseES) 数据库

目前许多政府项目对于使用国产数据库都会有强制要求,人大金仓和达梦是比较常见的国产数据库,项目中若使用国外开源的组件往往不能直接支持这些国产数据库,本文就以Liquibase 和 Flowable 6 支持人大金仓 (KingbaseES) 数据库为例,探讨此类国产数据库支持的基本思路。

Flowable 是一个基于 Java 的业务流程管理 (BPM) 和工作流引擎,内部实现使用mybatis操作数据库,Liquibase 是一个开源的数据库变更管理工具,这两个开源组件都支持多种常见的数据库包括oracle、mysql和postgresql等。

1. 依赖项

以下是示例的Flowable、Liquibase 和 Kingbase JDBC 驱动的依赖版本, pom.xml 配置:

<dependencies>
    <!-- Liquibase 核心依赖 -->
    <dependency>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-core</artifactId>
        <version>4.x.x</version> <!-- 使用所需的Liquibase版本 -->
    </dependency>

	<!-- Flowable 核心依赖 -->
    <dependency>
        <groupId>org.flowable</groupId>
		<artifactId>flowable-spring-configurator</artifactId>
        <version>6.x.x</version> <!-- 使用Flowable 6的版本 -->
    </dependency>

    <!-- 人大金仓数据库kingbase8驱动,最低可支持JDK1.8 -->
	<dependency>
	    <groupId>cn.com.kingbase</groupId>
	    <artifactId>kingbase8</artifactId>
	    <version>8.6.0</version>
	</dependency>
	<!--postgresql驱动
	<dependency>
	 	<groupId>org.postgresql</groupId>
	 	<artifactId>postgresql</artifactId>
	 	<version>42.x.x</version>
	</dependency>
    -->
</dependencies>

2. 使用postgresql驱动

PostgreSQL 其开源特性和丰富的功能使其成为许多开发者和企业的首选数据库解决方案,Flowable 和Liquibase 都是支持PostgreSQL,而Kingbase 又是基于PostgreSQL封装扩展的,基本上完全兼容PostgreSQL,因此很容易想到的一种集成方案就是尝试直接使用PostgreSQL 的JDBC驱动连接kingbase数据库。这种集成方式只需要在 application.propertiesapplication.yml 中配置数据源,使用 PostgreSQL的 JDBC URL即可,Flowable 和Liquibase 会根据驱动类型自动识别并使用PostgreSQL协议连接Kingbase数据库。

spring.datasource.url=jdbc:postgresql://<hostname>:<port>/<database>
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.datasource.driver-class-name=org.postgresql.Driver

3. 使用kingbase驱动

虽然直接使用PostgreSQL驱动连接Kingbase数据库是可行的,特别是从原PostgreSQL数据库迁移过来的或者只使用PostgreSQL支持的语法创建的Kingbase数据库其兼容性是比较好的,但Kingbase在PostgreSQL基础上还是做了很多对其他数据库的兼容如oracle、mysql等,以便这些数据库能快速迁移到Kingbase,另外在驱动层面Kingbase对异常信息也做了进一步的封装,因此应用层面使用Kingbase驱动连接此类非PostgreSQL迁移过来的数据库兼容性会更好。

application.propertiesapplication.yml 中配置数据源,使用 Kingbase 的 JDBC URL。

spring.datasource.url=jdbc:kingbase8://<hostname>:<port>/<database>
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.datasource.driver-class-name=com.kingbase8.Driver
Flowable支持Kingbase驱动

Flowable 需要一些特定的表来存储流程信息,Flowable也使用 Liquibase 来管理这些流程表的创建和更新操作,或者您也可以通过执行Flowable提供的PostgreSQL数据库的SQL脚本来创建这些流程表。对于ORM如mybatis、hibernate和Liquibase这些组件对多数据库类型的支持都是通过定义相应数据库的方言类来实现的。Flowable本身并没有提供数据库方言的扩展机制,其内部使用mybatis操作数据库,所以一种方案是为mybatis提供Kingbase的数据库方言,但考虑到Flowable对所有的数据库操作都已经通过api封装好了,而且实践中也不大需要直接去访问操作这些流程表,因此另外一种更简单的方案是利用Flowable和Kingbase对PostgreSQL的完全兼容特性,通过注册配置让Flowable能识别Kingbase驱动并映射到PostgreSQL的方言来连接Kingbase数据库,这种方案只需扩展Flowable的SpringProcessEngineConfiguration配置类注册映射Kingbase驱动类型为Flowable支持的PostgreSQL方言。

	@Bean
   	public SpringProcessEngineConfiguration processEngineConfiguration(){
    	SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration(){    		
    		public void initDatabaseType() {
    			//把kingbase映射成postgres(使用kingbase8驱动,数据库产品名称返回的是KingbaseES)
    			super.databaseTypeMappings.setProperty("KingbaseES", DATABASE_TYPE_POSTGRES);
    			//flowable根据databaseProductName从databaseTypeMappings获取数据库类型
    			super.initDatabaseType();
    		}
    	};
    	//若不显示设置要使用的databaseType,Flowable根据JDBC驱动返回的databaseProductName值从databaseTypeMappings获取数据库方言类型
    	//processEngineConfiguration.setDatabaseType("KingbaseES");
    	...
    	return processEngineConfiguration;
   	}
Liquibase支持Kingbase驱动

项目中集成 Liquibase主要是为了管理数据库变更,所有数据库变更都通过Liquibase来定义和执行,保证项目代码版本与数据库变更版本的一致性。Liquibase和Flowable不一样,我们需要为Liquibase提供Kingbase的数据库方言,以便支持在定义数据库变更操作时可以使用到Kingbase本身的一些特性。

package liquibase.database.core;

import liquibase.Scope;
import liquibase.database.DatabaseConnection;
import liquibase.exception.DatabaseException;
import liquibase.logging.Logger;
/**
 * 通过继承PostgresDatabase实现kingbase8数据库方言
 */
public class Kingbase8Database extends PostgresDatabase {
    public static final String PRODUCT_NAME = "KingbaseES";

    private static final int DEFAULT_TCP_PORT_NUMBER = 54321;//PGSQL为5432
    private static final Logger LOG = Scope.getCurrentScope().getLog(Kingbase8Database.class);
    @Override
    public String getShortName() {
        return "kingbase8";
    }
    @Override
    protected String getDefaultDatabaseProductName() {
        return PRODUCT_NAME;
    }
    @Override
    public Integer getDefaultPort() {
        return DEFAULT_TCP_PORT_NUMBER;
    }    
    @Override
    public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
        if (!PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName())) {
            return false;
        }
        //getDatabaseMajorVersion()返回的是12应该是Kingbase封装的postgre版本
        int majorVersion = conn.getDatabaseMajorVersion();
        int minorVersion = conn.getDatabaseMinorVersion();
        if (majorVersion < 12) {
            LOG.warning(
                String.format(
                    "Your Kingbase8 software version (%d.%d) seems to indicate that your software is " +
                    "older than %d.%d. This means that you might encounter strange behaviour and " + 
                    "incorrect error messages.", majorVersion, minorVersion, 12, 1));
        }
        return true;
    }
    @Override
    public String getDefaultDriver(String url) {
    	if (url.startsWith("jdbc:kingbase8:")) {
            return "com.kingbase8.Driver";
        }
        return null;
    }
    /**
     * Should the database use "serial" datatypes vs. "generated by default as identity"
     */
    public boolean useSerialDatatypes() {
    	//postgre10以上版本默认使用 "generated by default as identity"
    	//如果需要使用"serial" datatypes,则都返回true
    	return true;
    }
}
/** 
 * 使用Postgres驱动连接Kingbase8数据库
 * 如果没有洁癖(缺省端口一定要改成54321)或者序列创建不影响的话可以直接使用liquibase的PostgresDatabase
 */
public class PostgresKingbaseDatabase extends PostgresDatabase {
    private static final int DEFAULT_TCP_PORT_NUMBER = 54321;//PGSQL为5432
    @Override
    public Integer getDefaultPort() {
        return DEFAULT_TCP_PORT_NUMBER;
    } 
    /**
     * Should the database use "serial" datatypes vs. "generated by default as identity"
     */
    public boolean useSerialDatatypes() {    	
    	return true;
    }
    @Override
    public int getPriority() {
    	//提高优先级以便优先于liquibase自带的PostgresDatabase
        return PRIORITY_DATABASE;
    }
}

定义好Kingbase的数据库方言之后,还需要注册方言实现类让liquibase能识别。

@Configuration
public class LiquibaseConfig {
	static {
		// 注册到liquibase数据库工厂,其他方言liquibase的DatabaseFactory会通过扫描META-INF/services目录下的liquibase.database.Database文件来加载文件里定义的数据库方言实现类
		DatabaseFactory.getInstance().register(new Kingbase8Database());
		DatabaseFactory.getInstance().register(new PostgresKingbaseDatabase());
	}
	@Bean
    public SpringLiquibase liquibase(DataSource dataSource){
    	...
    }
}

总结

本文主要介绍了Liquibase 和 Flowable 6支持人大金仓国产数据库(Kingbase)时的相关集成方案。