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
服务启动成功日志
解决以上问题可以启动服务
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时出错:inStream参数为null分析解决 liquibase相关问题问题一:不支持的数据库 Error executing SQL call current_schema: 无法解析的成员访…...

VScode C语言学习开发环境;运行提示“#Include错误,无法打开源文件stdio.h”
C/C环境配置 参考: VS Code 配置 C/C 编程运行环境(保姆级教程)_vscode配置c环境-CSDN博客 基本步骤 - 安装MinGW-W64,其包含 GCC 编译器:bin目录添加到环境变量;CMD 中输入gcc --version或where gcc验证…...

DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
对于个人开发者或尝鲜者而言,本地想要部署 DeepSeek 有很多种方案,但是一旦涉及到企业级部署,则步骤将会繁琐很多。 比如我们的第一步就需要先根据实际业务场景评估出我们到底需要部署什么规格的模型,以及我们所要部署的模型&…...

自制简单的图片查看器(python)
图片格式:支持常见的图片格式(JPG、PNG、BMP、GIF)。 import os import tkinter as tk from tkinter import filedialog, messagebox from PIL import Image, ImageTkclass ImageViewer:def __init__(self, root):self.root rootself.root.…...
RD-搭建测试环境
测试团队职责 环境验证:确保开发部署的测试环境可访问,页面/接口无阻塞问题; 配置检查**:核对数据库连接、接口域名、HT证书等关键配置; 数据准备**:导入基线数据,隔离测试与生产数据࿱…...

从零搭建微服务项目Base(第5章——SpringBoot项目LogBack日志配置+Feign使用)
前言: 本章主要在原有项目上添加了日志配置,对SpringBoot默认的logback的配置进行了自定义修改,并详细阐述了xml文件配置要点(只对日志配置感兴趣的小伙伴可选择直接跳到第三节),并使用Feign代替原有RestT…...

【深度学习】使用飞桨paddle实现波士顿房价预测任务
使用飞桨实现波士顿房价预测任务 由于开始学习深度学习,因此每次开始都熟悉一下深度学习模型的基本步骤: 在之前的学习中,我们学习了使用Python和NumPy实现波士顿房价预测任务的方法,本章我们将尝试使用飞桨paddle重写房价预测任…...
钉钉多维表:数据管理与协作的新篇章
在当今数字化时代,数据的高效管理和团队协作已成为企业竞争力的关键因素之一。钉钉多维表,作为一款基于钉钉平台的数据协作管理工具,正以其独特的功能和优势,引领着数据管理与协作的新潮流。本文将为您全面解析钉钉多维表的定义、特点、功能亮点、应用场景以及如何使用,让您轻松…...

高级推理的多样化推理与验证
25年2月来自波士顿大学、NotBadMath.AI、谷歌、哥伦比亚大学、MIT、Intuit公司和斯坦福大学的论文“Diverse Inference and Verification for Advanced Reasoning”。 OpenAI o1、o3 和 DeepSeek R1 等推理 LLM 在数学和编码方面取得重大进展,但仍发现 IMO 组合问题…...
深入理解 MySQL 8 C++ 源码:SELECT MOD(MONTH(NOW()), 2) 的函数执行过程
MySQL 作为最流行的关系型数据库之一,其内部实现机制一直是开发者探索的热点。本文将以一条简单的 SQL 查询 SELECT MOD(MONTH(NOW()), 2) 为例,深入分析 MySQL 8 源码中内置函数 MOD、MONTH 和 NOW 的执行过程,揭示其底层实现逻辑。 一、SQL…...

【算法系列】leetcode1419 数青蛙 --模拟
一、题目 二、思路 模拟⻘蛙的叫声。 当遇到 r o a k 这四个字符的时候,我们要去看看每⼀个字符对应的前驱字符,有没有⻘蛙叫出来。如果有⻘蛙叫出来,那就让这个⻘蛙接下来喊出来这个字符;如果没有则为异常字符串,直接…...
蓝桥杯 Java B 组之背包问题、最长递增子序列(LIS)
Day 4:背包问题、最长递增子序列(LIS) 📖 一、动态规划(Dynamic Programming)简介 动态规划是一种通过将复杂问题分解成更小的子问题来解决问题的算法设计思想。它主要用于解决具有最优子结构和重叠子问题…...
Git如何将一个分支的内容同步到另一个分支
在 Git 中,可以通过多种方法将一个分支的内容同步到另一个分支。以下是几种常用的方法: 1. 使用 merge 命令 这是最常见的方法,将一个分支的更改合并到另一个分支。 # 切换到目标分支 git checkout target-branch# 合并源分支的内容 git m…...

[C#]C# winform部署yolov12目标检测的onnx模型
yolov12官方框架:github.com/sunsmarterjie/yolov12 【测试环境】 vs2019 netframework4.7.2 opencvsharp4.8.0 onnxruntime1.16.3 【效果展示】 【调用代码】 using System; using System.Collections.Generic; using System.ComponentModel; using System.…...

51c大模型~合集69
我自己的原文哦~ https://blog.51cto.com/whaosoft/12221979 #7项基于SAM万物分割模型研究工作 1、CC-SAM: SAM with Cross-feature Attention and Context for Ultrasound Image Segmentation #ECCV2024 #SAM #图像分割 #医学图像 Segment Anything Model (SAM) 在自…...
2025寒假周报4
2025寒假天梯训练7-CSDN博客 眨眼间寒假训练就告一段落了,准备回校继续战斗了。这周练了3场OI赛制的篮球杯,感觉非常糟糕,不像天梯赛,天梯赛打起来非常舒适顺畅,一直都不喜欢OI赛制,打着非常不稳定..还需要…...

自学Java-AI结合GUI开发一个石头迷阵的游戏
自学Java-AI结合GUI开发一个石头迷阵的游戏 准备环节1、创建石头迷阵的界面2、打乱顺序3、控制上下左右移动4、判断是否通关5、统计移动步骤,重启游戏6、拓展问题 准备环节 技术: 1、GUI界面编程 2、二维数组 3、程序流程控制 4、面向对象编程 ∙ \bulle…...

buuctf-[极客大挑战 2019]Knife题解
一个很简单的web题,进入界面 网页名还加白给的shell,并且给的提示也很明显,给了一个一句话木马再加上菜刀,很怀疑是一个webshell题,那么直接打开蚁剑测试连接拿shell 用提示的一句话木马的密码,测试链接发现…...
Spring MVC 对象转换器:初级开发者入门指南
Spring MVC 对象转换器:初级开发者入门指南 为什么需要对象转换器? 在 Web 应用中,我们经常需要处理不同类型的对象。例如:前端数据到后端对象 :用户通过表单提交的数据通常是HttpServletRequest 对象,我们…...

语音直播交友app出海:语音直播交友系统软件源码搭建国际化发展技术层面分析
随着移动互联网的普及和全球社交需求的增长以及国内如火如荼的Ai大模型引起的全球发展热潮,语音直播软件出海成为了具有巨大发展潜力的业务领域。以下是一些关键的技术方向,将为语音直播软件在国际市场的成功推广及搭建合作奠定基础。 通信技术 实时语音…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...

Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...

Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...