当前位置: 首页 > article >正文

flowable适配达梦数据库

文章目录

  • 适配相关问题
    • 无法从数据库产品名称“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;@Overridepublic void destroy() throws Exception {if (processEngine != null) {processEngine.close();}}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overridepublic 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 memberSpringProcessEngineConfiguration engineConfiguration = (SpringProcessEngineConfiguration) processEngineConfiguration;if (engineConfiguration.getTransactionManager() != null) {processEngineConfiguration.setTransactionsExternallyManaged(true);}}}@Overridepublic Class<ProcessEngine> getObjectType() {return ProcessEngine.class;}@Overridepublic 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 DBMSString 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.xmlinputStream = 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 propertiesproperties.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 设置propertiesproperties.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_DATABASECHANGELOGdatabase.setDatabaseChangeLogTableName(changeLogPrefix + database.getDatabaseChangeLogTableName());// 设置数据库更改日志锁定表名称  FLW_EV_DATABASECHANGELOGLOCKdatabase.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 usedif (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的DatabaseSortedSet<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";}@Overridepublic 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());}}}@Overridepublic 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*/@Overridepublic String getShortName() {return "dm";}/*** 默认数据库产品名称* @return*/@Overrideprotected String getDefaultDatabaseProductName() {return "DM DBMS";}@Overridepublic int getDatabaseMajorVersion() throws DatabaseException {return this.databaseMajorVersion == null ? super.getDatabaseMajorVersion() : this.databaseMajorVersion;}@Overridepublic int getDatabaseMinorVersion() throws DatabaseException {return this.databaseMinorVersion == null ? super.getDatabaseMinorVersion() : this.databaseMinorVersion;}/*** 端口* @return*/@Overridepublic Integer getDefaultPort() {return 5236;}@Overridepublic String getJdbcCatalogName(CatalogAndSchema schema) {return null;}@Overridepublic String getJdbcSchemaName(CatalogAndSchema schema) {return this.correctObjectName(schema.getCatalogName() == null ? schema.getSchemaName() : schema.getCatalogName(), Schema.class);}@Overrideprotected 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);}}@Overridepublic String generatePrimaryKeyName(String tableName) {return tableName.length() > 27 ? "PK_" + tableName.toUpperCase(Locale.US).substring(0, 27) : "PK_" + tableName.toUpperCase(Locale.US);}@Overridepublic boolean supportsInitiallyDeferrableColumns() {return true;}@Overridepublic boolean isReservedWord(String objectName) {return this.reservedWords.contains(objectName.toUpperCase());}@Overridepublic boolean supportsSequences() {return true;}@Overridepublic boolean supportsSchemas() {return false;}@Overrideprotected 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*/@Overridepublic boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {return "DM DBMS".equalsIgnoreCase(conn.getDatabaseProductName());}/*** jdbc 驱动* @param url* @return*/@Overridepublic String getDefaultDriver(String url) {return url.startsWith("jdbc:dm") ? "dm.jdbc.driver.DmDriver" : null;}@Overridepublic 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);}}@Overridepublic 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;}}@Overridepublic 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);}}@Overridepublic boolean supportsTablespaces() {return true;}@Overridepublic boolean supportsAutoIncrement() {boolean isAutoIncrementSupported = false;try {if (this.getDatabaseMajorVersion() >= 12) {isAutoIncrementSupported = true;}} catch (DatabaseException var3) {isAutoIncrementSupported = false;}return isAutoIncrementSupported;}@Overridepublic boolean supportsRestrictForeignKeys() {return false;}@Overridepublic 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 ") + ")";}@Overridepublic 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;}@Overridepublic 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\"");}}@Overridepublic 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;}@Overridepublic 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

调用了存储过程

解决

达梦没有这个存储过程 这些把值写死

   @Overridepublic 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

7.0.0.39新增字段

服务启动成功日志

解决以上问题可以启动服务

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....

相关文章:

flowable适配达梦数据库

文章目录 适配相关问题无法从数据库产品名称“DM DBMS”中推断数据库类型分析解决 构建ibatis SqlSessionFactory时出错&#xff1a;inStream参数为null分析解决 liquibase相关问题问题一&#xff1a;不支持的数据库 Error executing SQL call current_schema: 无法解析的成员访…...

Jenkins整合Jmeter实现接口自动化测试

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、安装jmeter 下载&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 这里我用了一台Windows安装jmeter用来写接口测试的脚本&#xff0c;启动前修改j…...

高级推理的多样化推理与验证

25年2月来自波士顿大学、NotBadMath.AI、谷歌、哥伦比亚大学、MIT、Intuit公司和斯坦福大学的论文“Diverse Inference and Verification for Advanced Reasoning”。 OpenAI o1、o3 和 DeepSeek R1 等推理 LLM 在数学和编码方面取得重大进展&#xff0c;但仍发现 IMO 组合问题…...

深入理解 MySQL 8 C++ 源码:SELECT MOD(MONTH(NOW()), 2) 的函数执行过程

MySQL 作为最流行的关系型数据库之一&#xff0c;其内部实现机制一直是开发者探索的热点。本文将以一条简单的 SQL 查询 SELECT MOD(MONTH(NOW()), 2) 为例&#xff0c;深入分析 MySQL 8 源码中内置函数 MOD、MONTH 和 NOW 的执行过程&#xff0c;揭示其底层实现逻辑。 一、SQL…...

清华大学:DeepSeek与AI幻觉(31页PDF)

PDF深入探讨了AI幻觉的概念、原因、评测方法及其实用应用&#xff0c;特别是在金融领域的具体案例。首先介绍了AI幻觉的定义&#xff0c;主要包括数据偏差、泛化困境、知识固化和意图误解四种情况&#xff0c;以及这些因素导致AI产出不合理结果的原因。随后&#xff0c;通过音乐…...

AWS云从业者认证题库 AWS Cloud Practitioner(2.21)

题库持续更新&#xff0c;上方二维码查看完整题库&#xff01; 公司希望减少开发人员用于运行代码的物理计算资源,通过启用无服务器架构&#xff0c;哪种服务可以满足该需求? A&#xff1a; Amazon Elastic Compute Cloud (Amazon EC2) B&#xff1a; AWS Lambda C&#xff1a…...

CompletableFuture 使用和源码解读

引言 CompletableFuture 是 Java 8 引入的一个强大的异步编程工具&#xff0c;用于处理异步操作和处理结果。它实现了 Future 和 CompletionStage 接口&#xff0c;提供了丰富的方法来处理异步任务的完成、组合和异常处理。 CompletableFuture本质是对异步线程的返回值…...

C++与Python:两种编程语言的区别

C和Python都是当今编程领域广泛使用的语言&#xff0c;它们各有特色&#xff0c;适用于不同的开发场景。本文将从语言特性、性能、学习难度、应用领域等多个方面探讨C与Python之间的区别。 一、语言特性 类型系统&#xff1a; C&#xff1a;是一种静态类型语言&#xf…...

网络工程师 (43)IP数据报

前言 IP数据报是互联网传输控制协议&#xff08;Internet Protocol&#xff0c;IP&#xff09;的数据报格式&#xff0c;由首部和数据两部分组成。 一、首部 IP数据报的首部是控制部分&#xff0c;包含了数据报传输和处理所需的各种信息。首部可以分为固定部分和可变部分。 固定…...

京准电钟:水利控制系统网络时间同步设计与应用

京准电钟&#xff1a;水利控制系统网络时间同步设计与应用 京准电钟&#xff1a;水利控制系统网络时间同步设计与应用 引言 在水利工程中&#xff0c;控制系统的高效运行依赖于精准的时间同步。水电站、泵站、闸门控制、水文监测等子系统的协同作业需要毫秒甚至微秒级的时间…...

QML 实现一个动态的启动界面

QML 实现一个动态的启动界面 一、效果查看二、源码分享三、所用到的资源下载 一、效果查看 二、源码分享 工程结构 main.qml import QtQuick import QtQuick.Controls import QtQuick.Dialogs import Qt.labs.platformWindow {id:windowwidth: 640height: 400visible: truetit…...

伪404兼容huawei生效显示404

根据上述思考&#xff0c;以下是详细的中文分步说明&#xff1a; --- **步骤 1&#xff1a;获取目标设备的User-Agent信息** 首先&#xff0c;我们需要收集目标设备的User-Agent字符串&#xff0c;包括&#xff1a; 1. **iPhone设备的User-Agent**&#xff1a; Mozi…...

程序代码篇---Python指明函数参数类型

文章目录 前言简介一、函数参数的类型指定1. 基本类型提示2. 默认参数3. 可变参数4. 联合类型&#xff08;Union&#xff09;5. 可选类型&#xff08;Optional&#xff09;6. 复杂类型 二、返回值的类型指定1. 基本返回类型2. 无返回值&#xff08;None&#xff09;3. 返回多个…...

【论文阅读】SAM-CP:将SAM与组合提示结合起来的多功能分割

导言 近年来&#xff0c;视觉基础模型的快速发展推动了多模态理解的进步&#xff0c;尤其是在图像分割任务中。例如&#xff0c;Segment Anything模型&#xff08;SAM&#xff09;在图像Mask分割上表现出色&#xff0c;但在语义及实例分割方面仍存在局限。本文提出的SAM-CP&am…...

ecovadis社会企业责任认证

EcoVadis 是一家全球性的企业社会责任 (CSR) 评级机构&#xff0c;旨在通过评估企业在环境、劳工与人权、商业道德和可持续采购等方面的表现&#xff0c;帮助提升其可持续性和社会责任实践。 EcoVadis 认证的核心内容 环境 评估企业在能源消耗、碳排放、废物管理等方面的表现。…...

机器视觉3D中,深度图与点云图数据对比分析

在机器视觉3D中,深度图(Depth Map)和点云图(Point Cloud)是两种不同的数据表示形式,主要区别如下: 数据维度与结构 深度图 二维矩阵:每个像素存储对应场景中某一点的深度值(即到相机的距离)。 坐标系:基于图像坐标系(2D),每个像素的坐标是 (u, v),对应的深度值为…...

逻辑架构与软件架构在PREEvision中的设计关系

1 Introduction 在如今汽车电子系统的开发过程中&#xff0c;系统架构设计是至关重要的环节。无论是汽车控制系统、信息娱乐系统&#xff0c;还是电动驱动系统&#xff0c;架构设计都决定了整个系统的功能、性能以及后期的可维护性和可扩展性。 在往期文章中&#xff0c;我们…...

机器学习和深度神经网络 参数调参数 太麻烦,非常费时间怎么办,用自动化超参数优化方法

自动化超参数优化方法主要包括以下几种‌&#xff1a; ‌网格搜索&#xff08;Grid Search&#xff09;‌&#xff1a;网格搜索是通过在给定的超参数搜索空间内尝试所有可能的组合&#xff0c;最后找出最优的超参数组合。这种方法虽然直观&#xff0c;但计算成本较高&#xff0…...

武汉火影数字|VR沉浸式空间制作 VR大空间打造

VR沉浸式空间制作是指通过虚拟现实技术创建一个逼真的三维环境&#xff0c;让用户能够沉浸在这个环境中&#xff0c;彷佛置身于一个全新的世界。 也许你会好奇&#xff0c;VR 沉浸式空间究竟是如何将我们带入那奇妙的虚拟世界的呢&#xff1f;这背后&#xff0c;离不开一系列关…...

MQTT的连接配置以及重连机制和遇到的问题--------求如何修改更加好

今天遇到了一个mqtt的问题&#xff0c;虽然解决了&#xff0c;但是感觉不是很好&#xff0c;希望大家多指点 这是配置文件 customer:mqtt:broker: tcp://ip:1883clientList:- clientId: nays_servicesubscribeTopic: xxxxxx- clientId: receive_servicesubscribeTopic: xxxxx…...

大数据学习之任务流调度系统Azkaban、Superset可视化系统

一.任务流调度系统Azkaban 1.课程介绍 2.为什么需要工作流调度系统 3.AZKABAN是什么 4.AZKABAN下载 5.制作安装包 6.tar包准备 7.MYSQL配置AZKABAN 8.配置EXECUTOR SERVER 9.配置WEBSERVER 10.单作业实战_yaml语言(今天稍晚更新) 11.单作业实战 12.多作业依赖实战 13.失败自动重…...

在VS-qt的程序中,后期增加PCH预编译功能,提高编译速度

由于前期创建qt程序的时候未勾选pch功能,导致没有启动预编译的功能. 这种情况下需要增加pch功能应该怎么做? 在项目中增加2个文件 stdafx.h和stdafx.cpp文件 stdafx.h增加qt常用头文件 #pragma once //windows #include <windows.h>//qt常用 #include <QObject&g…...

蓝桥云客 路径之谜

11.路径之谜 - 蓝桥云课 路径之谜 题目描述 小明冒充X星球的骑士&#xff0c;进入了一个奇怪的城堡。 城堡里边什么都没有&#xff0c;只有方形石头铺成的地面。 假设城堡地面是nn个方格。如下图所示。 按习俗&#xff0c;骑士要从西北角走到东南角。可以横向或纵向移动&…...

ES6相关操作

一.JavaScript的基础语法 1.Demo1.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>JavaScrip…...

在Linux上创建一个Docker容器并在其中执行Python脚本

在Linux上创建一个Docker容器并在其中执行Python脚本的过程&#xff0c;涉及多个方面的内容&#xff0c;包括安装Docker、编写Dockerfile、构建镜像、运行容器等。 1. 安装Docker 在Linux上使用Docker之前&#xff0c;你需要确保系统已安装Docker。Docker支持的Linux发行版有…...

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_os_init 函数

ngx_os_init 声明在 src/os/unix/ngx_os.h ngx_int_t ngx_os_init(ngx_log_t *log); 定义在 src\os\unix\ngx_posix_init.c ngx_int_t ngx_os_init(ngx_log_t *log) {ngx_time_t *tp;ngx_uint_t n; #if (NGX_HAVE_LEVEL1_DCACHE_LINESIZE)long size; #endif#if (NGX…...

【Python项目】基于Python的语音数据及标注核对审核系统

【Python项目】基于Python的语音数据及标注核对审核系统 技术简介&#xff1a; 采用Python技术、MySQL数据库、Django框架等实现。 系统简介&#xff1a; 语音数据及标注核对审核系统是一个基于B/S架构的语音数据处理平台&#xff0c;旨在通过自动化的方式对语音数据进行标…...

深入解析BFS算法:C++实现无权图最短路径的高效解决方案

在无权图中&#xff0c;广度优先搜索&#xff08;BFS&#xff09;是解决最短路径问题的高效算法。接下来博主从专业角度深入探讨其实现细节&#xff0c;并给出C代码示例&#xff1a; 目录 一、核心原理 二、算法步骤 三、C实现关键点 1. 数据结构 2. 边界检查 3. 路径回溯…...

LeetCode刷题---二分查找---441

排列硬币 441. 排列硬币 - 力扣&#xff08;LeetCode&#xff09; 题目 你总共有 n 枚硬币&#xff0c;并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯&#xff0c;其第 i 行必须正好有 i 枚硬币。阶梯的最后一行 可能 是不完整的。 给你一个数字 n &#xff0c;计算…...

Unity结合Vuforia虚拟按键实现AR机械仿真动画效果

零、最终效果 待上传 一、资源准备 1、Vuforia Vuforia版本不能高于10.17.4&#xff08;往上的版本虚拟按键功能被删除&#xff09; 2、Unity Unity版本必须要高于2022.3.x&#xff0c;不然使用Vuforia插件时会出现bug 二、主要内容 1、添加虚拟按钮 2、为虚拟按钮设置…...