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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/22054.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch公共方法封装

业务场景 1、RestClientBuilder初始化&#xff08;同时支持单机与集群&#xff09; 2、发送ES查询请求公共方法封装&#xff08;支持sql、kql、代理访问、集群访问、鉴权支持&#xff09; 3、判断ES索引是否存在&#xff08;/_cat/indices/${indexName}&#xff09; 4、判断ES…

题海拾贝:【枚举】P2010 [NOIP 2016 普及组] 回文日期

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 1、题…

《深入理解JVM》实战笔记(二): 类加载机制与类加载器

序言 Java 语言的强大之处之一在于其动态加载的能力&#xff0c;使得 Java 程序可以在运行时加载新的类&#xff0c;而不需要在编译时确定所有的类信息。这一切都离不开 JVM 的类加载机制。本篇博客将详细探讨 JVM 的类加载过程以及类加载器的工作原理&#xff0c;帮助你更深入…

vin码拍照识别-车牌识别api-vin码接口解析

在当今数字化飞速发展的背景下&#xff0c;如何高效、准确地管理和追踪车辆信息成为了众多企业和个人关注的焦点。VIN码&#xff08;Vehicle Identification Number&#xff09;和车牌作为车辆独一无二的身份标识&#xff0c;在车辆管理、保险理赔、二手车交易等多个场景中发挥…

Tomcat理论(Ⅰ)

目录 服务器流程图一览 一、JavaWeb前奏(了解) 1. C/S结构 2. B/S结构 3. 静态网页&动态网页 4.常见的网页 5.Web服务器 知名服务器&#xff1a; ​编辑 二、Tomcat安装&#xff08;熟练&#xff09; 1.Tomcat概述 2.Tomcat的作用 3.Tomcat安装 4.Tomcat测试 3.…

[实现Rpc] 通信-Muduo库的实现 | 完美转发 | reserve | unique_lock

目录 MudouBuffer ⭕右值引用 | 完美转发 右值引用 完美转发 实现原理 结合右值引用和完美转发的例子 LVProtocol ⭕vector 的 reserve 函数 1. 背景 2. reserve 函数原型 3. 示例代码 4. 输出结果 5. 结果解析 6. 关键点说明 MuduoConnection ⭕mudou 库 &am…

[OD E 100] 生成哈夫曼树

题目 题目描述 给定长度为 n 的无序的数字数组&#xff0c;每个数字代表二叉树的叶子节点的权值&#xff0c;数字数组的值均大于等于 1 。请完成一个函数&#xff0c;根据输入的数字数组&#xff0c;生成哈夫曼树&#xff0c;并将哈夫曼树按照中序遍历输出。 为了保证输出的二…

网络安全知识:网络安全概念、内容和主要技术纵览

21世纪全世界的计算机都将通过Internet联到一起&#xff0c;随着Internet的发展&#xff0c;网络丰富的信息资源给用户带来了极大的方便&#xff0c;但同时也给上网用户带来了安全问题。由于Internet的开放性和超越组织与国界等特点&#xff0c;使它在安全性上存在一些隐患。而…

【机器学习】多元线性回归算法和正规方程解求解

多元线性方差和正规方差解 一、摘要二、多元线性回归介绍三、正规方程解的求解及代码实现 一、摘要 本文围绕多元线性回归的正规方程解展开&#xff0c;为初学者系统介绍了相关基本概念、求解方法、实际应用以及算法封装要点。 首先&#xff0c;深入阐释了正规方程解这一多元…

Arcmap和ArcgisPro重装及配置迁移

近期要重装一下ArcgisPro&#xff0c;在此记录并作为大家的借鉴 1.备份配置文件&#xff1a;其中Desktop10.8为Arcmap的配置文件 2.通过控制面板卸载&#xff0c;arcpro卸载时间较长&#xff0c;先将语言包等卸载&#xff0c;最后再卸载5G主程序&#xff0c;有些文章会介绍清理…

【天线】IFA天线知识点摘抄

MIFA天线的尺寸与性能关系 1&#xff0c;辐射效率 天线越小&#xff0c;辐射效率越低。唯一好处是减少PCB占用空间 2&#xff0c;带宽 一般MIFA天线在2.4G频段内的带宽&#xff1a;S11≤-10dB的范围为2.44GHz230MHz。较小的尺寸可能会限制带宽 3&#xff0c;增益 MIFA天线的…

路由基本配置

学习目标 • 根据拓扑图进行网络布线。 • 清除启动配置并将路由器重新加载为默认状态。 • 在路由器上执行基本配置任务。 • 配置并激活以太网接口。 • 测试并检验配置。 • 思考网络实施方案并整理成文档。 任务 1&#xff1a;网络布线 使用适当的电缆类型连接网络设备。…

力扣27. 移除元素(快慢指针)

Problem: 27. 移除元素 文章目录 题目描述思路Code 题目描述 思路 定义快慢指针均指向数组起始位置&#xff0c;当fast指针指向的元素不等于val时将fast指针指向的元素赋值给slow并让slow指针向前移动&#xff0c;fast指针一直向前移动 时间复杂度: O ( n ) O(n) O(n); 空间复杂…

jemalloc 5.3.0里的快速路径分配逻辑及可借鉴的高性能编程思路

一、背景 jemalloc 5.3.0的介绍&#xff0c;我们已经持续了一段时间了&#xff0c;在 jemalloc 5.3.0的tsd模块的源码分析-CSDN博客 博客里&#xff0c;我们介绍了jemalloc的编译和调试&#xff0c;在 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展…

Vue前端开发-Vant之Layout组件

在Vant 中&#xff0c;Layout组件用于元素的响应式布局&#xff0c;分别由van-row和van-col两个组件来实现&#xff0c;前者表示行&#xff0c;后者被包裹在van-row组件中&#xff0c;表示列&#xff0c;共有24列栅格组成&#xff0c;在van-col组件中&#xff0c;span属性表示所…

【UCB CS 61B SP24】Lecture 5 - Lists 3: DLLists and Arrays学习笔记

本文内容为构建双向循环链表、使用 Java 的泛型将其优化为通用类型的链表以及数组的基本语法介绍。 1. 双向链表 回顾上一节课写的代码&#xff0c;当执行 addLast() 与 getLast() 方法时需要遍历链表&#xff0c;效率不高&#xff0c;因此可以添加一个指向链表末尾的索引&am…

Ubuntu 22.04 Install deepseek

前言 deepseekAI助手。它具有聊天机器人功能&#xff0c;可以与用户进行自然语言交互&#xff0c;回答问题、提供建议和帮助解决问题。DeepSeek 的特点包括&#xff1a; 强大的语言理解能力&#xff1a;能够理解和生成自然语言&#xff0c;与用户进行流畅的对话。多领域知识&…

边缘安全加速(ESA)套餐

为帮助不同规模和需求的企业选择合适的解决方案&#xff0c;边缘安全加速&#xff08;ESA&#xff09;提供了多种套餐。以下是四种主要套餐的介绍&#xff0c;每个套餐都根据企业需求提供不同的功能和服务水平&#xff0c;从基础安全保护到企业级的全面防护与加速。 1. 各版本详…

I²C简介

前言 IC&#xff08;Inter-Integrated Circuit, 内置集成电路&#xff09;总线是由Philips公司&#xff08;现属于恩智浦&#xff09;在上世纪80年代开发的两线式串行通信总线&#xff0c;用于连接微控制器及其外围设备&#xff0c;控制设备之间的通信。 IC总线的物理拓扑示意…

Frp部署文档

Frp部署文档 开源项目地址:https://github.com/fatedier/frp项目中文文档地址&#xff1a;https://github.com/fatedier/frp/blob/dev/README_zh.md官网文档地址: https://gofrp.org/zh-cn/docs/发布包地址&#xff1a;https://github.com/fatedier/frp/releases 要注意对应的…