文章目录
- 适配相关问题
- 无法从数据库产品名称“DM DBMS”中推断数据库类型
- 分析
- 解决
- 构建ibatis SqlSessionFactory时出错:inStream参数为null
- 分析
- 解决
- liquibase相关问题
- 问题一:不支持的数据库 Error executing SQL call current_schema: 无法解析的成员访问表达式[CURRENT_SCHEMA]
- 分析
- 解决
- 问题二:找不到 setRemarksReporting 方法
- 解决
- 问题三:存储过程问题问题,Cannot read from DBMS_UTILITY.DB_VERSION: 无效的方法名[DB_VERSION]
- 分析
- 解决
- 问题四: 更新事件注册表引擎表时出错、初始化事件注册表数据模型时出错
- 解决
- 问题五:验证事件注册表引擎架构时出错
- 解决
- 数据库版本问题version mismatch: library version is '7.0.1.1', db version is 7.0.0.0
- 解决
- 启动流程相关问题
- 解决
- 服务启动成功日志
网上flowable7新版本适配文档较少,以下使用部署flowable7源码方式说明相关适配问题。
适配相关问题
无法从数据库产品名称“DM DBMS”中推断数据库类型
分析
先查看较为完整的堆栈信息调用流程看一下怎么个事
实例化bean 类型为class com.xxxx.workflow.service.impl.ProcessServiceImp
通过反射实例化后,填充属性,依赖注入
主要看注入flowable内置的Service
解析taskService字段
解析依赖关系
根据beanName(taskServiceBean)和type(org.flowable.engine.TaskService)得到要注入的实例
给taskService属性赋值
以上执行完就给taskSerive字段属性赋值了,报错是在执行
org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate方法时,也就是实例化taskService的时候
实例化taskService
从bena定义信息中可以看出有工厂方法 返回的是taskService
所以通过工厂方法实例化
得到候选实例的参数
解析注入参数processEngine
根据beanName(processEngine)和type(org.flowable.engine.ProcessEngine)得到要注入的实例
实例化processEngine
从bean定义信息中可以看出是通过 ProcessEngineFactoryBean 定制化创建的ProcessEngine,在ProcessEngineFactoryBean的getOject方法中会构建流程引擎
public class ProcessEngineFactoryBean implements FactoryBean<ProcessEngine>, DisposableBean, ApplicationContextAware {
protected ProcessEngineConfigurationImpl processEngineConfiguration;
protected ApplicationContext applicationContext;
protected ProcessEngine processEngine;
@Override
public void destroy() throws Exception {
if (processEngine != null) {
processEngine.close();
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public ProcessEngine getObject() throws Exception {
configureExternallyManagedTransactions();
if (processEngineConfiguration.getBeans() == null) {
processEngineConfiguration.setBeans(new SpringBeanFactoryProxyMap(applicationContext));
}
// 构建流程引擎
this.processEngine = processEngineConfiguration.buildProcessEngine();
return this.processEngine;
}
protected void configureExternallyManagedTransactions() {
if (processEngineConfiguration instanceof SpringProcessEngineConfiguration) { // remark: any config can be injected, so we cannot have SpringConfiguration as member
SpringProcessEngineConfiguration engineConfiguration = (SpringProcessEngineConfiguration) processEngineConfiguration;
if (engineConfiguration.getTransactionManager() != null) {
processEngineConfiguration.setTransactionsExternallyManaged(true);
}
}
}
@Override
public Class<ProcessEngine> getObjectType() {
return ProcessEngine.class;
}
@Override
public boolean isSingleton() {
return true;
}
public ProcessEngineConfigurationImpl getProcessEngineConfiguration() {
return processEngineConfiguration;
}
public void setProcessEngineConfiguration(ProcessEngineConfigurationImpl processEngineConfiguration) {
this.processEngineConfiguration = processEngineConfiguration;
}
}
通过ProcessEngineFactoryBean的getOject获取processEngine实例的对象
重点在这里
org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl#buildProcessEngine 构建流程引擎
org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl#init 初始化
org.flowable.common.engine.impl.AbstractEngineConfiguration#initDataSource 初始化数据源
org.flowable.common.engine.impl.AbstractEngineConfiguration#initDatabaseType 初始化数据源类型 databaseProductName为DM DBMS
从org.flowable.common.engine.impl.AbstractEngineConfiguration#getDefaultDatabaseTypeMappings 从数据库类型映射中获取DM DBMS看看有没有,没有则抛出异常
public void initDatabaseType() {
Connection connection = null;
try {
connection = dataSource.getConnection();
DatabaseMetaData databaseMetaData = connection.getMetaData();
//databaseProductName为DM DBMS
String databaseProductName = databaseMetaData.getDatabaseProductName();
logger.debug("database product name: '{}'", databaseProductName);
// 如果是PostgreSQL,做一下处理...
if (PRODUCT_NAME_POSTGRES.equalsIgnoreCase(databaseProductName)) {
try (PreparedStatement preparedStatement = connection.prepareStatement("select version() as version;");
ResultSet resultSet = preparedStatement.executeQuery()) {
String version = null;
if (resultSet.next()) {
version = resultSet.getString("version");
}
if (StringUtils.isNotEmpty(version) && version.toLowerCase().startsWith(PRODUCT_NAME_CRDB.toLowerCase())) {
databaseProductName = PRODUCT_NAME_CRDB;
logger.info("CockroachDB version '{}' detected", version);
}
}
}
//从org.flowable.common.engine.impl.AbstractEngineConfiguration#getDefaultDatabaseTypeMappings获取DM DBMS看看有没有
databaseType = databaseTypeMappings.getProperty(databaseProductName);
if (databaseType == null) {
throw new FlowableException("couldn't deduct database type from database product name '" + databaseProductName + "'");
}
logger.debug("using database type: {}", databaseType);
} catch (SQLException e) {
throw new RuntimeException("Exception while initializing Database connection", e);
} finally {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
logger.error("Exception while closing the Database connection", e);
}
}
if (DATABASE_TYPE_MSSQL.equals(databaseType)) {
maxNrOfStatementsInBulkInsert = DEFAULT_MAX_NR_OF_STATEMENTS_BULK_INSERT_SQL_SERVER;
}
}
public static Properties getDefaultDatabaseTypeMappings() {
Properties databaseTypeMappings = new Properties();
databaseTypeMappings.setProperty("H2", DATABASE_TYPE_H2);
databaseTypeMappings.setProperty("HSQL Database Engine", DATABASE_TYPE_HSQL);
databaseTypeMappings.setProperty("MySQL", DATABASE_TYPE_MYSQL);
databaseTypeMappings.setProperty("MariaDB", DATABASE_TYPE_MYSQL);
databaseTypeMappings.setProperty("Oracle", DATABASE_TYPE_ORACLE);
databaseTypeMappings.setProperty(PRODUCT_NAME_POSTGRES, DATABASE_TYPE_POSTGRES);
databaseTypeMappings.setProperty("Microsoft SQL Server", DATABASE_TYPE_MSSQL);
databaseTypeMappings.setProperty(DATABASE_TYPE_DB2, DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/NT", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/NT64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2 UDP", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUX", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUX390", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUXX8664", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUXZ64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUXPPC64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUXPPC64LE", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/400 SQL", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/6000", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2 UDB iSeries", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/AIX64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/HPUX", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/HP64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/SUN", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/SUN64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/PTX", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/2", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2 UDB AS400", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty(PRODUCT_NAME_CRDB, DATABASE_TYPE_COCKROACHDB);
return databaseTypeMappings;
}
解决
添加达梦数据库类型映射
org.flowable.common.engine.impl.AbstractEngineConfiguration
构建ibatis SqlSessionFactory时出错:inStream参数为null
分析
定位
上面流程初始化了数据源,数据源类型等
在org.flowable.common.engine.impl.AbstractEngineConfiguration#initSqlSessionFactory初始化SqlSessionFactory,会根据数据源类型读取配置org/flowable/common/db/properties/dm.properties,没有dm的配置(mybatis分页相关配置),报InputStream为null
public void initSqlSessionFactory() {
if (sqlSessionFactory == null) {
InputStream inputStream = null;
try {
// 读取org/flowable/db/mapping/mappings.xml
inputStream = getMyBatisXmlConfigurationStream();
Environment environment = new Environment("default", transactionFactory, dataSource);
Reader reader = new InputStreamReader(inputStream);
Properties properties = new Properties();
properties.put("prefix", databaseTablePrefix);
String wildcardEscapeClause = "";
if ((databaseWildcardEscapeCharacter != null) && (databaseWildcardEscapeCharacter.length() != 0)) {
wildcardEscapeClause = " escape '" + databaseWildcardEscapeCharacter + "'";
}
properties.put("wildcardEscapeClause", wildcardEscapeClause);
// set default properties
properties.put("limitBefore", "");
properties.put("limitAfter", "");
properties.put("limitBetween", "");
properties.put("limitBeforeNativeQuery", "");
properties.put("limitAfterNativeQuery", "");
properties.put("blobType", "BLOB");
properties.put("boolValue", "TRUE");
if (databaseType != null) {
// 读取org/flowable/common/db/properties/dm.properties 设置properties
properties.load(getResourceAsStream(pathToEngineDbProperties()));
}
//
Configuration configuration = initMybatisConfiguration(environment, reader, properties);
sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
} catch (Exception e) {
throw new FlowableException("Error while building ibatis SqlSessionFactory: " + e.getMessage(), e);
} finally {
IoUtil.closeSilently(inputStream);
}
} else {
applyCustomMybatisCustomizations(sqlSessionFactory.getConfiguration());
}
}
解决
添加dm.properties 参考oracle
limitBefore=select RES.* from ( select RES.*, rownum as rnum from (
limitAfter= ) RES where ROWNUM < #{lastRow} ) RES where rnum >= #{firstRow}
boolValue=1
liquibase相关问题
liquibase版本为4.20.0
问题一:不支持的数据库 Error executing SQL call current_schema: 无法解析的成员访问表达式[CURRENT_SCHEMA]
liquibase.exception.DatabaseException: Error executing SQL call current_schema: 第1 行附近出现错误:
无法解析的成员访问表达式[CURRENT_SCHEMA]
分析
定位
org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl#buildProcessEngine
org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl#init
org.flowable.common.engine.impl.AbstractEngineConfiguration#configuratorsAfterInit
org.flowable.eventregistry.impl.EventRegistryEngineConfiguration#buildEventRegistryEngine
org.flowable.eventregistry.impl.EventRegistryEngineConfiguration#init
org.flowable.eventregistry.impl.EventRegistryEngineImpl 实例化
org.flowable.eventregistry.impl.db.EventDbSchemaManager#initSchema
org.flowable.common.engine.impl.db.LiquibaseBasedSchemaManager#createLiquibaseInstance 创建Liquibase实例
protected Liquibase createLiquibaseInstance(LiquibaseDatabaseConfiguration databaseConfiguration) throws SQLException {
Connection jdbcConnection = null;
boolean closeConnection = false;
try {
CommandContext commandContext = Context.getCommandContext();
if (commandContext == null) {
jdbcConnection = databaseConfiguration.getDataSource().getConnection();
closeConnection = true;
} else {
jdbcConnection = commandContext.getSession(DbSqlSession.class).getSqlSession().getConnection();
}
if (!jdbcConnection.getAutoCommit()) {
jdbcConnection.commit();
}
// 创建jdbc连接
DatabaseConnection connection = new JdbcConnection(jdbcConnection);
// 创建数据库实例
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);
// 设置数据库更改日志表名称 FLW_EV_DATABASECHANGELOG
database.setDatabaseChangeLogTableName(changeLogPrefix + database.getDatabaseChangeLogTableName());
// 设置数据库更改日志锁定表名称 FLW_EV_DATABASECHANGELOGLOCK
database.setDatabaseChangeLogLockTableName(changeLogPrefix + database.getDatabaseChangeLogLockTableName());
String databaseSchema = databaseConfiguration.getDatabaseSchema();
if (StringUtils.isNotEmpty(databaseSchema)) {
database.setDefaultSchemaName(databaseSchema);
database.setLiquibaseSchemaName(databaseSchema);
}
String databaseCatalog = databaseConfiguration.getDatabaseCatalog();
if (StringUtils.isNotEmpty(databaseCatalog)) {
database.setDefaultCatalogName(databaseCatalog);
database.setLiquibaseCatalogName(databaseCatalog);
}
return new Liquibase(changeLogFile, new ClassLoaderResourceAccessor(), database);
} catch (Exception e) {
// We only close the connection if an exception occurred, otherwise the Liquibase instance cannot be used
if (jdbcConnection != null && closeConnection) {
jdbcConnection.close();
}
throw new FlowableException("Error creating " + context + " liquibase instance", e);
}
}
liquibase.database.DatabaseFactory#findCorrectDatabaseImplementation 实例化所有实现了AbstractJdbcDatabase的Database,根据数据库连接获取数据库实现
public Database findCorrectDatabaseImplementation(DatabaseConnection connection) throws DatabaseException {
// 实例化所有实现了AbstractJdbcDatabase的Database
SortedSet<Database> foundDatabases = new TreeSet(new DatabaseComparator());
Iterator var3 = this.getImplementedDatabases().iterator();
while(var3.hasNext()) {
Database implementedDatabase = (Database)var3.next();
if (connection instanceof OfflineConnection) {
if (((OfflineConnection)connection).isCorrectDatabaseImplementation(implementedDatabase)) {
foundDatabases.add(implementedDatabase);
}
// 通过连接的数据库产品名判断 return "DM DBMS".equalsIgnoreCase(conn.getDatabaseProductName());
} else if (implementedDatabase.isCorrectDatabaseImplementation(connection)) {
foundDatabases.add(implementedDatabase);
}
}
// 没有找到实现
if (foundDatabases.isEmpty()) {
LOG.warning("Unknown database: " + connection.getDatabaseProductName());
// 返回一个不支持的数据库
UnsupportedDatabase unsupportedDB = new UnsupportedDatabase();
// 设置连接
unsupportedDB.setConnection(connection);
return unsupportedDB;
} else {
Database returnDatabase;
try {
returnDatabase = (Database)((Database)foundDatabases.iterator().next()).getClass().getConstructor().newInstance();
} catch (Exception var5) {
throw new UnexpectedLiquibaseException(var5);
}
returnDatabase.setConnection(connection);
return returnDatabase;
}
}
没有达梦数据库实现,返回一个不支持的数据库实例
设置连接时,执行报错
解决
liquibase.database.DatabaseFactory 查看实例化Database方式
liquibase.servicelocator.StandardServiceLocator#findInstances 通过Java SPI机制实现
所以根据SPI实现方式 创建达梦数据库实现 (暂且放在业务工程中,后面可以搞一个单独的集成工程 或 直接添加到flowable源码中)
创建AbstractJdbcDatabase实现类DMDatabase 参考liquibase.database.core.OracleDatabase实现修改
package com.xxxx.workflow.database;
/**
* @Author Chow
* @Date 2024/12/27 17:44
* @Version 1.0
* @description
**/
public class DMDatabase extends AbstractJdbcDatabase {
public static final Pattern PROXY_USER = Pattern.compile(".*(?:thin|oci)\\:(.+)/@.*");
/**
* 产品名称
*/
public static final String PRODUCT_NAME = "DM DBMS";
private static ResourceBundle coreBundle = ResourceBundle.getBundle("liquibase/i18n/liquibase-core");
protected final int SHORT_IDENTIFIERS_LENGTH = 30;
protected final int LONG_IDENTIFIERS_LEGNTH = 128;
public static final int ORACLE_12C_MAJOR_VERSION = 12;
private Set<String> reservedWords = new HashSet();
private Set<String> userDefinedTypes;
private Map<String, String> savedSessionNlsSettings;
private Boolean canAccessDbaRecycleBin;
private Integer databaseMajorVersion;
private Integer databaseMinorVersion;
public DMDatabase() {
super.unquotedObjectsAreUppercased = true;
super.setCurrentDateTimeFunction("SYSTIMESTAMP");
this.dateFunctions.add(new DatabaseFunction("SYSDATE"));
this.dateFunctions.add(new DatabaseFunction("SYSTIMESTAMP"));
this.dateFunctions.add(new DatabaseFunction("CURRENT_TIMESTAMP"));
super.sequenceNextValueFunction = "%s.nextval";
super.sequenceCurrentValueFunction = "%s.currval";
}
@Override
public int getPriority() {
return 1;
}
private void tryProxySession(String url, Connection con) {
Matcher m = PROXY_USER.matcher(url);
if (m.matches()) {
Properties props = new Properties();
props.put("PROXY_USER_NAME", m.group(1));
Method method;
try {
method = con.getClass().getMethod("openProxySession", Integer.TYPE, Properties.class);
method.setAccessible(true);
method.invoke(con, 1, props);
} catch (Exception var8) {
Scope.getCurrentScope().getLog(this.getClass()).info("Could not open proxy session on DMDatabase: " + var8.getCause().getMessage());
return;
}
try {
method = con.getClass().getMethod("isProxySession");
method.setAccessible(true);
boolean b = (Boolean) method.invoke(con);
if (!b) {
Scope.getCurrentScope().getLog(this.getClass()).info("Proxy session not established on DMDatabase: ");
}
} catch (Exception var7) {
Scope.getCurrentScope().getLog(this.getClass()).info("Could not open proxy session on DMDatabase: " + var7.getCause().getMessage());
}
}
}
@Override
public void setConnection(DatabaseConnection conn) {
this.reservedWords.addAll(Arrays.asList("GROUP", "USER", "SESSION", "PASSWORD", "RESOURCE", "START", "SIZE", "UID", "DESC", "ORDER"));
Connection sqlConn = null;
if (!(conn instanceof OfflineConnection)) {
try {
if (conn instanceof JdbcConnection) {
sqlConn = ((JdbcConnection) conn).getWrappedConnection();
}
} catch (Exception var29) {
throw new UnexpectedLiquibaseException(var29);
}
if (sqlConn != null) {
this.tryProxySession(conn.getURL(), sqlConn);
try {
this.reservedWords.addAll(Arrays.asList(sqlConn.getMetaData().getSQLKeywords().toUpperCase().split(",\\s*")));
} catch (SQLException var28) {
Scope.getCurrentScope().getLog(this.getClass()).info("Could get sql keywords on DMDatabase: " + var28.getMessage());
}
/**
* 在Oracle数据库中,setRemarksReporting是一个用于设置数据库对象(如表、视图、列等)注释或描述的方法。这通常用于生成数据库文档。
*/
try {
Method method = sqlConn.getClass().getMethod("setRemarksReporting", Boolean.TYPE);
method.setAccessible(true);
method.invoke(sqlConn, true);
} catch (Exception var27) {
Scope.getCurrentScope().getLog(this.getClass()).info("Could not set remarks reporting on DMDatabase: " + var27.getMessage());
}
CallableStatement statement = null;
// 基于oracle的实现修改 存储过程问题,无效的方法名[DB_VERSION] 这里直接写死
String sql;
try {
DatabaseMetaData metaData = sqlConn.getMetaData();
Connection connection = metaData.getConnection();
Connection connection1 = connection.getMetaData().getConnection();
//String compatibleVersion = "11.2.0.4.0"; //这个是oracleDatabase 当前使用的数据库版本
String compatibleVersion = "8.1.3.100";
Matcher majorVersionMatcher = Pattern.compile("(\\d+)\\.(\\d+)\\..*").matcher(compatibleVersion);
if (majorVersionMatcher.matches()) {
this.databaseMajorVersion = Integer.valueOf(majorVersionMatcher.group(1));
this.databaseMinorVersion = Integer.valueOf(majorVersionMatcher.group(2));
}
} catch (SQLException var25) {
sql = "Cannot read from DBMS_UTILITY.DB_VERSION: " + var25.getMessage();
Scope.getCurrentScope().getLog(this.getClass()).info("Could not set check compatibility mode on DMDatabase, assuming not running in any sort of compatibility mode: " + sql);
} finally {
JdbcUtil.closeStatement(statement);
}
if (GlobalConfiguration.DDL_LOCK_TIMEOUT.getCurrentValue() != null) {
int timeoutValue = (Integer) GlobalConfiguration.DDL_LOCK_TIMEOUT.getCurrentValue();
Scope.getCurrentScope().getLog(this.getClass()).fine("Setting DDL_LOCK_TIMEOUT value to " + timeoutValue);
sql = "ALTER SESSION SET DDL_LOCK_TIMEOUT=" + timeoutValue;
PreparedStatement ddlLockTimeoutStatement = null;
try {
ddlLockTimeoutStatement = sqlConn.prepareStatement(sql);
ddlLockTimeoutStatement.execute();
} catch (SQLException var23) {
Scope.getCurrentScope().getUI().sendErrorMessage("Unable to set the DDL_LOCK_TIMEOUT_VALUE: " + var23.getMessage(), var23);
Scope.getCurrentScope().getLog(this.getClass()).warning("Unable to set the DDL_LOCK_TIMEOUT_VALUE: " + var23.getMessage(), var23);
} finally {
JdbcUtil.closeStatement(ddlLockTimeoutStatement);
}
}
}
}
super.setConnection(conn);
}
/**
* 简称
* @return
*/
@Override
public String getShortName() {
return "dm";
}
/**
* 默认数据库产品名称
* @return
*/
@Override
protected String getDefaultDatabaseProductName() {
return "DM DBMS";
}
@Override
public int getDatabaseMajorVersion() throws DatabaseException {
return this.databaseMajorVersion == null ? super.getDatabaseMajorVersion() : this.databaseMajorVersion;
}
@Override
public int getDatabaseMinorVersion() throws DatabaseException {
return this.databaseMinorVersion == null ? super.getDatabaseMinorVersion() : this.databaseMinorVersion;
}
/**
* 端口
* @return
*/
@Override
public Integer getDefaultPort() {
return 5236;
}
@Override
public String getJdbcCatalogName(CatalogAndSchema schema) {
return null;
}
@Override
public String getJdbcSchemaName(CatalogAndSchema schema) {
return this.correctObjectName(schema.getCatalogName() == null ? schema.getSchemaName() : schema.getCatalogName(), Schema.class);
}
@Override
protected String getAutoIncrementClause(String generationType, Boolean defaultOnNull) {
if (StringUtil.isEmpty(generationType)) {
return super.getAutoIncrementClause();
} else {
String autoIncrementClause = "GENERATED %s AS IDENTITY";
String generationStrategy = generationType;
if (Boolean.TRUE.equals(defaultOnNull) && generationType.toUpperCase().equals("BY DEFAULT")) {
generationStrategy = generationType + " ON NULL";
}
return String.format(autoIncrementClause, generationStrategy);
}
}
@Override
public String generatePrimaryKeyName(String tableName) {
return tableName.length() > 27 ? "PK_" + tableName.toUpperCase(Locale.US).substring(0, 27) : "PK_" + tableName.toUpperCase(Locale.US);
}
@Override
public boolean supportsInitiallyDeferrableColumns() {
return true;
}
@Override
public boolean isReservedWord(String objectName) {
return this.reservedWords.contains(objectName.toUpperCase());
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsSchemas() {
return false;
}
@Override
protected String getConnectionCatalogName() throws DatabaseException {
if (this.getConnection() instanceof OfflineConnection) {
return this.getConnection().getCatalog();
} else if (!(this.getConnection() instanceof JdbcConnection)) {
return this.defaultCatalogName;
} else {
try {
return (String) ((ExecutorService) Scope.getCurrentScope().getSingleton(ExecutorService.class)).getExecutor("jdbc", this).queryForObject(new RawCallStatement("select sys_context( 'userenv', 'current_schema' ) from dual"), String.class);
} catch (Exception var2) {
Scope.getCurrentScope().getLog(this.getClass()).info("Error getting default schema", var2);
return null;
}
}
}
/**
* 根据数据库连接判断是否是该数据库实现
* {@link liquibase.database.DatabaseFactory#findCorrectDatabaseImplementation(liquibase.database.DatabaseConnection)}
* {@link Database#isCorrectDatabaseImplementation(DatabaseConnection)}
* @param conn
* @return
* @throws DatabaseException
*/
@Override
public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
return "DM DBMS".equalsIgnoreCase(conn.getDatabaseProductName());
}
/**
* jdbc 驱动
* @param url
* @return
*/
@Override
public String getDefaultDriver(String url) {
return url.startsWith("jdbc:dm") ? "dm.jdbc.driver.DmDriver" : null;
}
@Override
public String getDefaultCatalogName() {
String defaultCatalogName = super.getDefaultCatalogName();
if (Boolean.TRUE.equals(GlobalConfiguration.PRESERVE_SCHEMA_CASE.getCurrentValue())) {
return defaultCatalogName;
} else {
return defaultCatalogName == null ? null : defaultCatalogName.toUpperCase(Locale.US);
}
}
@Override
public String getDateLiteral(String isoDate) {
String normalLiteral = super.getDateLiteral(isoDate);
if (this.isDateOnly(isoDate)) {
return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD')";
} else if (this.isTimeOnly(isoDate)) {
return "TO_DATE(" + normalLiteral + ", 'HH24:MI:SS')";
} else if (this.isTimestamp(isoDate)) {
return "TO_TIMESTAMP(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS.FF')";
} else if (this.isDateTime(isoDate)) {
int seppos = normalLiteral.lastIndexOf(46);
if (seppos != -1) {
normalLiteral = normalLiteral.substring(0, seppos) + "'";
}
return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS')";
} else {
return "UNSUPPORTED:" + isoDate;
}
}
@Override
public boolean isSystemObject(DatabaseObject example) {
if (example == null) {
return false;
} else if (this.isLiquibaseObject(example)) {
return false;
} else {
if (example instanceof Schema) {
label131:
{
if (!"SYSTEM".equals(example.getName()) && !"SYS".equals(example.getName()) && !"CTXSYS".equals(example.getName()) && !"XDB".equals(example.getName())) {
if (!"SYSTEM".equals(example.getSchema().getCatalogName()) && !"SYS".equals(example.getSchema().getCatalogName()) && !"CTXSYS".equals(example.getSchema().getCatalogName()) && !"XDB".equals(example.getSchema().getCatalogName())) {
break label131;
}
return true;
}
return true;
}
} else if (this.isSystemObject(example.getSchema())) {
return true;
}
if (example instanceof Catalog) {
if ("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName())) {
return true;
}
} else if (example.getName() != null) {
if (example.getName().startsWith("BIN$")) {
boolean filteredInOriginalQuery = this.canAccessDbaRecycleBin();
if (!filteredInOriginalQuery) {
filteredInOriginalQuery = StringUtil.trimToEmpty(example.getSchema().getName()).equalsIgnoreCase(this.getConnection().getConnectionUserName());
}
if (!filteredInOriginalQuery) {
return true;
}
return !(example instanceof PrimaryKey) && !(example instanceof Index) && !(example instanceof UniqueConstraint);
}
if (example.getName().startsWith("AQ$")) {
return true;
}
if (example.getName().startsWith("DR$")) {
return true;
}
if (example.getName().startsWith("SYS_IOT_OVER")) {
return true;
}
if ((example.getName().startsWith("MDRT_") || example.getName().startsWith("MDRS_")) && example.getName().endsWith("$")) {
return true;
}
if (example.getName().startsWith("MLOG$_")) {
return true;
}
if (example.getName().startsWith("RUPD$_")) {
return true;
}
if (example.getName().startsWith("WM$_")) {
return true;
}
if ("CREATE$JAVA$LOB$TABLE".equals(example.getName())) {
return true;
}
if ("JAVA$CLASS$MD5$TABLE".equals(example.getName())) {
return true;
}
if (example.getName().startsWith("ISEQ$$_")) {
return true;
}
if (example.getName().startsWith("USLOG$")) {
return true;
}
if (example.getName().startsWith("SYS_FBA")) {
return true;
}
}
return super.isSystemObject(example);
}
}
@Override
public boolean supportsTablespaces() {
return true;
}
@Override
public boolean supportsAutoIncrement() {
boolean isAutoIncrementSupported = false;
try {
if (this.getDatabaseMajorVersion() >= 12) {
isAutoIncrementSupported = true;
}
} catch (DatabaseException var3) {
isAutoIncrementSupported = false;
}
return isAutoIncrementSupported;
}
@Override
public boolean supportsRestrictForeignKeys() {
return false;
}
@Override
public int getDataTypeMaxParameters(String dataTypeName) {
if ("BINARY_FLOAT".equals(dataTypeName.toUpperCase())) {
return 0;
} else {
return "BINARY_DOUBLE".equals(dataTypeName.toUpperCase()) ? 0 : super.getDataTypeMaxParameters(dataTypeName);
}
}
public String getSystemTableWhereClause(String tableNameColumn) {
List<String> clauses = new ArrayList(Arrays.asList("BIN$", "AQ$", "DR$", "SYS_IOT_OVER", "MLOG$_", "RUPD$_", "WM$_", "ISEQ$$_", "USLOG$", "SYS_FBA"));
for (int i = 0; i < clauses.size(); ++i) {
clauses.set(i, tableNameColumn + " NOT LIKE '" + (String) clauses.get(i) + "%'");
}
return "(" + StringUtil.join(clauses, " AND ") + ")";
}
@Override
public boolean jdbcCallsCatalogsSchemas() {
return true;
}
public Set<String> getUserDefinedTypes() {
if (this.userDefinedTypes == null) {
this.userDefinedTypes = new HashSet();
if (this.getConnection() != null && !(this.getConnection() instanceof OfflineConnection)) {
try {
try {
this.userDefinedTypes.addAll(((ExecutorService) Scope.getCurrentScope().getSingleton(ExecutorService.class)).getExecutor("jdbc", this).queryForList(new RawSqlStatement("SELECT DISTINCT TYPE_NAME FROM ALL_TYPES"), String.class));
} catch (DatabaseException var2) {
this.userDefinedTypes.addAll(((ExecutorService) Scope.getCurrentScope().getSingleton(ExecutorService.class)).getExecutor("jdbc", this).queryForList(new RawSqlStatement("SELECT TYPE_NAME FROM USER_TYPES"), String.class));
}
} catch (DatabaseException var3) {
}
}
}
return this.userDefinedTypes;
}
@Override
public String generateDatabaseFunctionValue(DatabaseFunction databaseFunction) {
if (databaseFunction != null && "current_timestamp".equalsIgnoreCase(databaseFunction.toString())) {
return databaseFunction.toString();
} else if (!(databaseFunction instanceof SequenceNextValueFunction) && !(databaseFunction instanceof SequenceCurrentValueFunction)) {
return super.generateDatabaseFunctionValue(databaseFunction);
} else {
String quotedSeq = super.generateDatabaseFunctionValue(databaseFunction);
return quotedSeq.replaceFirst("\"([^.\"]+)\\.([^.\"]+)\"", "\"$1\".\"$2\"");
}
}
@Override
public ValidationErrors validate() {
ValidationErrors errors = super.validate();
DatabaseConnection connection = this.getConnection();
if (connection != null && !(connection instanceof OfflineConnection)) {
if (!this.canAccessDbaRecycleBin()) {
errors.addWarning(this.getDbaRecycleBinWarning());
}
return errors;
} else {
Scope.getCurrentScope().getLog(this.getClass()).info("Cannot validate offline database");
return errors;
}
}
public String getDbaRecycleBinWarning() {
return "Liquibase needs to access the DBA_RECYCLEBIN table so we can automatically handle the case where constraints are deleted and restored. Since Oracle doesn't properly restore the original table names referenced in the constraint, we use the information from the DBA_RECYCLEBIN to automatically correct this issue.\n\nThe user you used to connect to the database (" + this.getConnection().getConnectionUserName() + ") needs to have \"SELECT ON SYS.DBA_RECYCLEBIN\" permissions set before we can perform this operation. Please run the following SQL to set the appropriate permissions, and try running the command again.\n\n GRANT SELECT ON SYS.DBA_RECYCLEBIN TO " + this.getConnection().getConnectionUserName() + ";";
}
public boolean canAccessDbaRecycleBin() {
if (this.canAccessDbaRecycleBin == null) {
DatabaseConnection connection = this.getConnection();
if (connection == null || connection instanceof OfflineConnection) {
return false;
}
Statement statement = null;
try {
statement = ((JdbcConnection) connection).createStatement();
ResultSet resultSet = statement.executeQuery("select 1 from dba_recyclebin where 0=1");
resultSet.close();
this.canAccessDbaRecycleBin = true;
} catch (Exception var7) {
if (var7 instanceof SQLException && var7.getMessage().startsWith("ORA-00942")) {
this.canAccessDbaRecycleBin = false;
} else {
Scope.getCurrentScope().getLog(this.getClass()).warning("Cannot check dba_recyclebin access", var7);
this.canAccessDbaRecycleBin = false;
}
} finally {
JdbcUtil.close((ResultSet) null, statement);
}
}
return this.canAccessDbaRecycleBin;
}
@Override
public boolean supportsNotNullConstraintNames() {
return true;
}
public boolean isValidOracleIdentifier(String identifier, Class<? extends DatabaseObject> type) {
if (identifier != null && identifier.length() >= 1) {
if (!identifier.matches("^(i?)[A-Z][A-Z0-9\\$\\_\\#]*$")) {
return false;
} else {
return identifier.length() <= 128;
}
} else {
return false;
}
}
public int getIdentifierMaximumLength() {
try {
if (this.getDatabaseMajorVersion() < 12) {
return 30;
} else {
return this.getDatabaseMajorVersion() == 12 && this.getDatabaseMinorVersion() <= 1 ? 30 : 128;
}
} catch (DatabaseException var2) {
throw new UnexpectedLiquibaseException("Cannot determine the DM database version number", var2);
}
}
}
新建META-INF/services/liquibase.database.Database文件,添加DMDatabase全路径名
再次运行可以找到dm数据库实现
进入else
问题二:找不到 setRemarksReporting 方法
Could not set remarks reporting on OracleDatabase: jdk.proxy2.$Proxy147.setRemarksReporting(boolean)
Method threw ‘java.lang.NoSuchMethodException’ exception. 找不到 setRemarksReporting 方法
定位
com.xxxx.workflow.database.DMDatabase#setConnection
解决
反射调用了 JDBC 连接对象setRemarksReporting 方法
Oracle数据库中 setRemarksReporting用于设置数据库对象注释的方法,用来生成数据库文档。
这个dm的数据库实现可以直接注释
问题三:存储过程问题问题,Cannot read from DBMS_UTILITY.DB_VERSION: 无效的方法名[DB_VERSION]
Could not set check compatibility mode on OracleDatabase, assuming not running in any sort of compatibility mode: Cannot read from DBMS_UTILITY.DB_VERSION: 第1 行附近出现错误:无效的方法名[DB_VERSION]
分析
定位
com.xxxx.workflow.database.DMDatabase#setConnection
调用了存储过程
解决
达梦没有这个存储过程 这些把值写死
@Override
public void setConnection(DatabaseConnection conn) {
this.reservedWords.addAll(Arrays.asList("GROUP", "USER", "SESSION", "PASSWORD", "RESOURCE", "START", "SIZE", "UID", "DESC", "ORDER"));
Connection sqlConn = null;
if (!(conn instanceof OfflineConnection)) {
try {
if (conn instanceof JdbcConnection) {
sqlConn = ((JdbcConnection) conn).getWrappedConnection();
}
} catch (Exception var29) {
throw new UnexpectedLiquibaseException(var29);
}
if (sqlConn != null) {
this.tryProxySession(conn.getURL(), sqlConn);
try {
this.reservedWords.addAll(Arrays.asList(sqlConn.getMetaData().getSQLKeywords().toUpperCase().split(",\\s*")));
} catch (SQLException var28) {
Scope.getCurrentScope().getLog(this.getClass()).info("Could get sql keywords on OracleDatabase: " + var28.getMessage());
}
try {
Method method = sqlConn.getClass().getMethod("setRemarksReporting", Boolean.TYPE);
method.setAccessible(true);
method.invoke(sqlConn, true);
} catch (Exception var27) {
Scope.getCurrentScope().getLog(this.getClass()).info("Could not set remarks reporting on OracleDatabase: " + var27.getMessage());
}
CallableStatement statement = null;
String sql;
try {
DatabaseMetaData metaData = sqlConn.getMetaData();
Connection connection = metaData.getConnection();
Connection connection1 = connection.getMetaData().getConnection();
//String compatibleVersion = "11.2.0.4.0"; //这个是oracleDatabase 当前使用的数据库版本
String compatibleVersion = "8.1.3.100";
Matcher majorVersionMatcher = Pattern.compile("(\\d+)\\.(\\d+)\\..*").matcher(compatibleVersion);
if (majorVersionMatcher.matches()) {
this.databaseMajorVersion = Integer.valueOf(majorVersionMatcher.group(1));
this.databaseMinorVersion = Integer.valueOf(majorVersionMatcher.group(2));
}
} catch (SQLException var25) {
sql = "Cannot read from DBMS_UTILITY.DB_VERSION: " + var25.getMessage();
Scope.getCurrentScope().getLog(this.getClass()).info("Could not set check compatibility mode on OracleDatabase, assuming not running in any sort of compatibility mode: " + sql);
} finally {
JdbcUtil.closeStatement(statement);
}
if (GlobalConfiguration.DDL_LOCK_TIMEOUT.getCurrentValue() != null) {
int timeoutValue = (Integer) GlobalConfiguration.DDL_LOCK_TIMEOUT.getCurrentValue();
Scope.getCurrentScope().getLog(this.getClass()).fine("Setting DDL_LOCK_TIMEOUT value to " + timeoutValue);
sql = "ALTER SESSION SET DDL_LOCK_TIMEOUT=" + timeoutValue;
PreparedStatement ddlLockTimeoutStatement = null;
try {
ddlLockTimeoutStatement = sqlConn.prepareStatement(sql);
ddlLockTimeoutStatement.execute();
} catch (SQLException var23) {
Scope.getCurrentScope().getUI().sendErrorMessage("Unable to set the DDL_LOCK_TIMEOUT_VALUE: " + var23.getMessage(), var23);
Scope.getCurrentScope().getLog(this.getClass()).warning("Unable to set the DDL_LOCK_TIMEOUT_VALUE: " + var23.getMessage(), var23);
} finally {
JdbcUtil.closeStatement(ddlLockTimeoutStatement);
}
}
}
}
super.setConnection(conn);
}
参考:https://blog.csdn.net/zhangdaiscott/article/details/134547342
问题四: 更新事件注册表引擎表时出错、初始化事件注册表数据模型时出错
解决
将flowable.database-schema-update设置为false
应用启动时不会更新数据库模式,如果数据库模式和 Flowable 版本不匹配,会抛出异常阻止应用启动。
问题五:验证事件注册表引擎架构时出错
liquibase.Liquibase#validate
liquibase.executor.jvm.JdbcExecutor#execute(liquibase.statement.SqlStatement, java.util.List<liquibase.sql.visitor.SqlVisitor>)
解决
liquibase.Liquibase#validate 验证数据库模式与变更日志文件一致性,这里直接注释掉。
数据库版本问题version mismatch: library version is ‘7.0.1.1’, db version is 7.0.0.0
解决
参考flowable源码当前版 修改为对应版本
也可以数据源先使用mysql,再做迁移
启动流程相关问题
由于flowable.database-schema-update设置为false,如果数据表结构等和 Flowable 版本不匹配,不会进行自动更新,当前表直接迁移的是原7.0.0版本的表结构,源码部署的是GA版本的7.0.0分支(实际版本为7.0.0.39),两个版本的初始化表数量一样,但表结构字段有不同。
列找不到
解决
表结构可以先使用mysql生成,迁移到dm
服务启动成功日志
解决以上问题可以启动服务
Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@1750724866 wrapping dm.jdbc.driver.DmdbConnection@657f1fc3]]
2024-12-30 17:12:19.969 [main] INFO o.f.i.e.i.IdmEngineImpl -
[<init>,52] - IdmEngine default created
2024-12-30 17:12:19.986 [main] INFO o.f.s.SpringProcessEngineConfiguration -
[configuratorsAfterInit,1157] - Executing configure() of class org.flowable.dmn.spring.configurator.SpringDmnEngineConfigurator (priority:200000)
Opening JDBC Connection
2024-12-30 17:12:30.646 [main] INFO liquibase.database -
[log,37] - Could not set remarks reporting on OracleDatabase: jdk.proxy2.$Proxy147.setRemarksReporting(boolean)
Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@1026432280 wrapping dm.jdbc.driver.DmdbConnection@657f1fc3]]
2024-12-30 17:12:35.406 [main] INFO o.f.d.e.i.DmnEngineImpl -
[<init>,55] - DmnEngine default created
2024-12-30 17:12:35.415 [main] INFO o.f.s.SpringProcessEngineConfiguration -
[configuratorsAfterInit,1157] - Executing configure() of class org.flowable.cmmn.spring.configurator.SpringCmmnEngineConfigurator (priority:500000)
Opening JDBC Connection
2024-12-30 17:12:45.684 [main] INFO liquibase.database -
[log,37] - Could not set remarks reporting on OracleDatabase: jdk.proxy2.$Proxy147.setRemarksReporting(boolean)
Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@8603972 wrapping dm.jdbc.driver.DmdbConnection@657f1fc3]]
2024-12-30 17:12:52.094 [main] INFO o.f.c.e.i.CmmnEngineImpl -
[<init>,72] - CmmnEngine default created
Opening JDBC Connection
==> Preparing: select VALUE_ from ACT_GE_PROPERTY where NAME_ = 'schema.version'
==> Parameters:
<== Columns: VALUE_
<== Row: 7.0.1.1
<== Total: 1
Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@530287651 wrapping dm.jdbc.driver.DmdbConnection@657f1fc3]]
2024-12-30 17:12:52.443 [main] INFO o.f.e.i.ProcessEngineImpl -
[<init>,89] - ProcessEngine default created
Opening JDBC Connection
==> Preparing: select count(RES.ID_) from ACT_RE_DEPLOYMENT RES WHERE RES.ENGINE_VERSION_ = ?
==> Parameters: v5(String)
<== Columns: COUNT(RES.ID_)
<== Row: 0
<== Total: 1
2024-12-30 17:12:52.937 [main] INFO o.f.e.i.c.ValidateV5EntitiesCmd -
[execute,43] - Total of v5 deployments found: 0
Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@871541777 wrapping dm.jdbc.driver.DmdbConnection@657f1fc3]]
Opening JDBC Connection
==> Preparing: select * from ACT_GE_PROPERTY where NAME_ = ?
==> Parameters: cfg.execution-related-entities-count(String)
<== Columns: NAME_, VALUE_, REV_
<== Row: cfg.execution-related-entities-count, true, 1
<== Total: 1
Closing JDBC Connection [Transaction-aware proxy for target Connection [HikariProxyConnection@1059563867 wrapping dm.jdbc.driver.DmdbConnection@657f1fc3]]
Opening JDBC Connection
==> Preparing: select * from ACT_GE_PROPERTY where NAME_ = ?
==> Parameters: cfg.task-related-entities-count(String)
<== Columns: NAME_, VALUE_, REV_
<== Row: cfg.task-related-entities-count, true, 1
<== Total: 1
....