若依以及flowbale达梦国产化数据库改造

Springboot与flowable—达梦国产化改造

文章目录

  • Springboot与flowable—达梦国产化改造
    • 1、相关软件下载
      • 1.1 下载可视化工具
    • 2 、源代码运行
      • 2.1 导入sql
      • 2.2 打开项目,导入pom依赖
      • 2.3 修改配置
      • 2.3.1 修改数据库配置
      • 2.3.2 修改redis配置
      • 2.3.3 运行后端
      • 2.3.4 运行前端
    • 3、数据库迁移
      • 3.1 新建达梦数据库(用户)
        • 3.1.1 用户授权
      • 3.2 使用数据库迁移工具
        • 3.2.1 新建工程
        • 3.2.2 新建迁移
    • 4、springboot替换为达梦数据库
      • 4.1 安装达梦驱动jar包
      • 4.2 POM添加达梦的驱动依赖
      • 4.3 修改yml的达梦连接驱动
    • 5、flowable工作流整合达梦数据库
      • 5.1 修改 AbstractEngineConfiguration 文件
      • 5.2 修改[liquibase](https://so.csdn.net/so/search?q=liquibase&spm=1001.2101.3001.7020)-core-4.3.5.jar中源码
      • 5.3 修改 liquibase.datatype.core.BooleanType类
      • 5.4 修改resources/META-INF.services/liquibase.database.Database
      • 5.5 报错
    • 6、替换修改项目中的sql
      • 6.1 替换 find_in_set函数
      • 6.2 替换case()函数
      • 6.3 根据达梦的主键自增修改SQL
      • 6.4 修改替换date_format 函数
      • 6.5 不支持 case-when-then-else
    • 7 、附注
      • 7.1 源码的修改方式
      • 7.2 启动Maven项目 程序包不存在报错
      • 7.3 mysql与达梦的部分sql函数差异

首先说明本实例包含了

1、达梦数据库迁移

2、SpringBoot与flowable工作流(flowable版本是6.7.0)替换达梦数据库

3、xml中的sql替换

这篇文章应该是全网最细的应该没错吧,收藏吧~

后面的东方通TongWeb的改造以及部署会写在我的另一篇文章。

1、相关软件下载

访问达梦官网:

达梦官网

1.1 下载可视化工具

首先注册一个账号

若依以及flowbale达梦国产化数据库改造

下载勾选指定版本的数据库管理工具 x86 、win64

若依以及flowbale达梦国产化数据库改造

解压压缩包

若依以及flowbale达梦国产化数据库改造

双击.iso文件,setup.exe傻瓜式安装。

注意:点击初始化

若依以及flowbale达梦国产化数据库改造

创建数据库实例

若依以及flowbale达梦国产化数据库改造

一直下一步,完成。

若依以及flowbale达梦国产化数据库改造

安装完会有这些软件,如下:一般用到的是数据库管理工具和迁移工具

若依以及flowbale达梦国产化数据库改造

若依以及flowbale达梦国产化数据库改造

ps: 数据库管理工具中管理员的用户名和密码都是 SYSDBA

注意达梦数据库名就对应创建的用户名 ,模式就对应数据库也即用户对象,但是一个用户也有可能会创建多个模式,这样就有可能需要在Springboot项目的配置文件里指定默认的模式(数据库)。

2 、源代码运行

先拿到要改造的项目的初始代码,运行起来,保证没改造之前是可行的。

2.1 导入sql

省略

2.2 打开项目,导入pom依赖

如果install有如下问题:

若依以及flowbale达梦国产化数据库改造

这个问题一般就是test下的测试类有问题,造成编译时失败,比如在控制台执行命令 mvn test

报错如下:

若依以及flowbale达梦国产化数据库改造

**解决办法:**编译install的时候先跳过test的执行,需要在pom.xml的里添加以下配置,使得测试出错不影响项目的编译。

pom中加入如下依赖

    
        
            org.apache.maven.plugins
            maven-surefire-plugin
            
                true
            
        
    

加完之后 clean install 然后重新编译 点击这个 m 图标 输入 mvn idea:idea

若依以及flowbale达梦国产化数据库改造

2.3 修改配置

2.3.1 修改数据库配置

若依以及flowbale达梦国产化数据库改造

2.3.2 修改redis配置

若依以及flowbale达梦国产化数据库改造

2.3.3 运行后端

直接运行

2.3.4 运行前端

首先打开前端控制台,下载依赖

npm install 

然后修改 vue.config.js配置文件中的代理配置(这里的代理地址就是访问后端接口的地址),连上后端

若依以及flowbale达梦国产化数据库改造

然后保存ctrl+s,一定要记得保存配置才生效

npm run dev

3、数据库迁移

把本地的mysql数据库迁移到达梦数据库。(首先这里迁移为了不影响之前的项目代码,我选择把源代码备份了一份,并新建备份了一个mysql数据库,修改了yml中的配置连接,下面会详细介绍)

迁移我选择了用上面安装的达梦数据库迁移工具

若依以及flowbale达梦国产化数据库改造

3.1 新建达梦数据库(用户)

上面提到过,达梦的数据库就对应用户对象,所以现在新建用户(数据库)

若依以及flowbale达梦国产化数据库改造

这里用户名就是数据库名,只能为大写,密码就是和mysql差不多的用户密码

3.1.1 用户授权

若依以及flowbale达梦国产化数据库改造

系统授权

若依以及flowbale达梦国产化数据库改造

点击确定,这里会提示失败,不用管,关闭后刷新用户,已经新建成功。

此时,用户和数据库已经建好了。模式就对应数据库。里面有对应的数据库表。

若依以及flowbale达梦国产化数据库改造

3.2 使用数据库迁移工具

SYSDBA密码默认就是SYSDBA

若依以及flowbale达梦国产化数据库改造

3.2.1 新建工程

若依以及flowbale达梦国产化数据库改造

3.2.2 新建迁移

若依以及flowbale达梦国产化数据库改造

点击下一步

若依以及flowbale达梦国产化数据库改造

选择mysql到dm,下一步.

若依以及flowbale达梦国产化数据库改造

连接源mysql数据库,首先指定驱动

若依以及flowbale达梦国产化数据库改造

本地先下载mysql驱动

mysql驱动

链接:https://pan.baidu.com/s/1nRELoWeRzcklpEtK8MNtYA

提取码:1111

若依以及flowbale达梦国产化数据库改造

填写完下一步

若依以及flowbale达梦国产化数据库改造

同理,指定达梦驱动,与数据库

达梦驱动链接:https://pan.baidu.com/s/1CDg2nMwY0s94Lp3gQ3j2cQ

提取码:1111

下一步

去掉使用默认数据类型映射关系的勾,然后点击右边配置类型映射关系按钮

点击右下角添加,原数据类型名VARCHAR,目的数据类型名VARCHAR,目的精度扩大倍数填入4,确定

若依以及flowbale达梦国产化数据库改造

选择需要迁移到的达梦数据库(模式),下一步

若依以及flowbale达梦国产化数据库改造

选择勾选指定的表,下一步

若依以及flowbale达梦国产化数据库改造

点击完成

这里有一个报错信息,记录超长

若依以及flowbale达梦国产化数据库改造

解决方案:先在达梦下执行设置表为记录超长脚本,删除数据再重新迁此表数据(在达梦数据库管理工具修改表)。

# 选择模式
set schema TRADING_CENTER_DM;
alter table SYS_OPER_LOG enable using long row;
truncate table SYS_OPER_LOG;
select * from SYS_OPER_LOG;

若依以及flowbale达梦国产化数据库改造

回到迁移工具,上一步,选择模式,选择表重新迁移这张失败的表即可。

这里数据库就迁移完了。

4、springboot替换为达梦数据库

4.1 安装达梦驱动jar包

jar包地址在上面迁移的时候有发过

若依以及flowbale达梦国产化数据库改造

把jar包安装到maven仓库

mvn install:install-file -Dfile=E:\Dameng\DmJdbcDriver18.jar -DgroupId=com.dm -DartifactId=DmJdbcDriver18 -Dversion=1.8 -Dpackaging=jar

若依以及flowbale达梦国产化数据库改造

4.2 POM添加达梦的驱动依赖

在admin模块添加达梦的驱动依赖

	
    
        com.dm
        DmJdbcDriver18
        1.8
    

若依以及flowbale达梦国产化数据库改造

此时重启项目会遇到编译报错,在没加pom依赖之前是可以启动的,加了之后启动编译build构建就会报错。所以先修改连接驱动yml配置。

4.3 修改yml的达梦连接驱动

# 数据源配置
spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
#        driverClassName: com.mysql.cj.jdbc.Driver
        driverClassName: dm.jdbc.driver.DmDriver
        druid:
            # 主库数据源
#            master:
#                url: jdbc:mysql://121.43.234.114:3306/trading_center?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
#                username: root
#                password: gds12345678
             #主库数据源(本地mysql数据库)
#            master:
#                url: jdbc:mysql://localhost:3306/trading_center_dm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
#                username: root
#                password: 123
            # 主库数据源(本地达梦数据库)
            master:
                url: jdbc:dm://127.0.0.1:5236?TRADING_CENTER_DM&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8
                username: SYSDBA
                password: SYSDBA
            # 从库数据源
            slave:
                # 从数据源开关/默认关闭
                enabled: false
                url:
                username:
                password:
            # 初始连接数
            initialSize: 5
            # 最小连接池数量
            minIdle: 10
            # 最大连接池数量
            maxActive: 20
            # 配置获取连接等待超时的时间
            maxWait: 60000
            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
            timeBetweenEvictionRunsMillis: 60000
            # 配置一个连接在池中最小生存的时间,单位是毫秒
            minEvictableIdleTimeMillis: 300000
            # 配置一个连接在池中最大生存的时间,单位是毫秒
            maxEvictableIdleTimeMillis: 900000
            # 配置检测连接是否有效
            validationQuery: SELECT 1 FROM DUAL
            testWhileIdle: true
            testOnBorrow: false
            testOnReturn: false
            webStatFilter:
                enabled: true
            statViewServlet:
                enabled: true
                # 设置白名单,不填则允许所有访问
                allow:
                url-pattern: /druid/*
                # 控制台管理用户名和密码
                login-username: ruoyi
                login-password: 123456
            filter:
                stat:
                    enabled: true
                    # 慢SQL记录
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    merge-sql: true
                wall:
                    config:
                        multi-statement-allow: true

参考上面的修改,记得达梦数据库名就是用户名。

注意url中数据库的格式 为 ?数据库名 和mysql的不一样,不然的话就会url有下面这种网络通信异常。

报错信息:

16:46:16.112 [restartedMain] ERROR c.a.d.p.DruidDataSource - [init,931] - init datasource error, url: jdbc:dm://127.0.0.1:5236/TRADING_CENTER_DM?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8
dm.jdbc.driver.DMException: 网络通信异常
	at dm.jdbc.driver.DBError.throwException(DBError.java:774)
	at dm.jdbc.a.a.init(DBAccess.java:185)
	at dm.jdbc.a.a.(DBAccess.java:157)
	at dm.jdbc.driver.DmdbConnection.openConnection(DmdbConnection.java:638)
	at dm.jdbc.desc.EP.connect(EP.java:159)
	at dm.jdbc.desc.EPGroup$EPSelector.select(EPGroup.java:395)
	at dm.jdbc.desc.EPGroup.connect(EPGroup.java:278)
	at dm.jdbc.driver.DmDriver.do_connect(DmDriver.java:163)
	at dm.jdbc.driver.DmDriver.connect(DmDriver.java:449)
	at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:156)
	at com.alibaba.druid.filter.stat.StatFilter.connection_connect(StatFilter.java:251)
	at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150)

然后由于本项目使用了flowable,启动后会出现工作流找不到驱动类型的报错如下,、

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'processEngine': FactoryBean threw exception on object creation; nested exception is org.flowable.common.engine.api.FlowableException: couldn't deduct database type from database product name 'DM DBMS'

所以还得修改flowable整合达梦的问题。

5、flowable工作流整合达梦数据库

pom依赖和修改达梦驱动参考上面的介绍。下面主要是介绍flowable整合达梦。(flowable的版本是6.7.0)

自动加载数据源时,flowable无法识别DM数据库类型,采用覆盖源码,(就是在java包路径下创建与源码类相同的的路径,把源代码全部复制到这个类里面,然后在修改达梦的代码)。设置成MySQL或者Oracle的数据库类型,需要修改文件:

5.1 修改 AbstractEngineConfiguration 文件

在项目中创建org.flowable.common.engine.impl.AbstractEngineConfiguration文件(这边路径必须一致,打包时会覆盖源文件),修改其中getDefaultDatabaseTypeMappings方法,将达梦数据库标识为mysql(value值设置为其他值会报错空指针。所以通用mysql),复制完源码后修改源码里面的这个方法,如下

public static final String DATABASE_TYPE_DM = "mysql"; //达梦 value值设置为其他值会报错空指针。所以通用mysql

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);
        databaseTypeMappings.setProperty("DM DBMS", DATABASE_TYPE_DM);// 加入达梦支持
        return databaseTypeMappings;
    }

5.2 修改liquibase-core-4.3.5.jar中源码

在java文件夹下创建DmDatabase类,全路径为liquibase.database.core.DmDatabase,参考了liquibase.database.core.OracleDatabase类,将下面代码直接粘进新创建的类。

在这个类中由作者介绍更改如下:

删除setConnection方法;

修改PRODUCT_NAME常量值为“DM DBMS”;

修改getDefaultPort方法,返回5236;

修改getShortName方法,返回dm;

修改getDefaultDriver方法,返回达梦的Driver;

下面这个代码可以直接复制我的,上面那个代码注意需要自己修改

package liquibase.database.core;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import liquibase.CatalogAndSchema;
import liquibase.Scope;
import liquibase.database.AbstractJdbcDatabase;
import liquibase.database.DatabaseConnection;
import liquibase.database.OfflineConnection;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.exception.ValidationErrors;
import liquibase.executor.ExecutorService;
import liquibase.statement.DatabaseFunction;
import liquibase.statement.SequenceCurrentValueFunction;
import liquibase.statement.SequenceNextValueFunction;
import liquibase.statement.core.RawCallStatement;
import liquibase.statement.core.RawSqlStatement;
import liquibase.structure.DatabaseObject;
import liquibase.structure.core.Catalog;
import liquibase.structure.core.Index;
import liquibase.structure.core.PrimaryKey;
import liquibase.structure.core.Schema;
import liquibase.util.JdbcUtils;
import liquibase.util.StringUtil;

public class DmDatabase extends AbstractJdbcDatabase {
    private static final String PRODUCT_NAME = "DM DBMS";

    @Override
    protected String getDefaultDatabaseProductName() {
        return PRODUCT_NAME;
    }

    /**
     * Is this AbstractDatabase subclass the correct one to use for the given connection.
     *
     * @param conn
     */
    @Override
    public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
        return PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName());
    }

    /**
     * If this database understands the given url, return the default driver class name.  Otherwise return null.
     *
     * @param url
     */
    @Override
    public String getDefaultDriver(String url) {
        if (url.startsWith("jdbc:dm")) {
            return "dm.jdbc.driver.DmDriver";
        }

        return null;
    }

    /**
     * Returns an all-lower-case short name of the product.  Used for end-user selecting of database type
     * such as the DBMS precondition.
     */
    @Override
    public String getShortName() {
        return "dm";
    }

    @Override
    public Integer getDefaultPort() {
        return 5236;
    }

    /**
     * Returns whether this database support initially deferrable columns.
     */
    @Override
    public boolean supportsInitiallyDeferrableColumns() {
        return true;
    }

    @Override
    public boolean supportsTablespaces() {
        return true;
    }

    @Override
    public int getPriority() {
        return PRIORITY_DEFAULT;
    }

    private static final Pattern PROXY_USER = Pattern.compile(".*(?:thin|oci)\\:(.+)/@.*");

    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 reservedWords = new HashSet();
    private Set userDefinedTypes;
    private Map savedSessionNlsSettings;

    private Boolean canAccessDbaRecycleBin;
    private Integer databaseMajorVersion;
    private Integer databaseMinorVersion;

    /**
     * Default constructor for an object that represents the Oracle Database DBMS.
     */
    public DmDatabase() {
        super.unquotedObjectsAreUppercased = true;
        //noinspection HardCodedStringLiteral
        super.setCurrentDateTimeFunction("SYSTIMESTAMP");
        // Setting list of Oracle's native functions
        //noinspection HardCodedStringLiteral
        dateFunctions.add(new DatabaseFunction("SYSDATE"));
        //noinspection HardCodedStringLiteral
        dateFunctions.add(new DatabaseFunction("SYSTIMESTAMP"));
        //noinspection HardCodedStringLiteral
        dateFunctions.add(new DatabaseFunction("CURRENT_TIMESTAMP"));
        //noinspection HardCodedStringLiteral
        super.sequenceNextValueFunction = "%s.nextval";
        //noinspection HardCodedStringLiteral
        super.sequenceCurrentValueFunction = "%s.currval";
    }

    private void tryProxySession(final String url, final Connection con) {
        Matcher m = PROXY_USER.matcher(url);
        if (m.matches()) {
            Properties props = new Properties();
            props.put("PROXY_USER_NAME", m.group(1));
            try {
                Method method = con.getClass().getMethod("openProxySession", int.class, Properties.class);
                method.setAccessible(true);
                method.invoke(con, 1, props);
            } catch (Exception e) {
                Scope.getCurrentScope().getLog(getClass()).info("Could not open proxy session on OracleDatabase: " + e.getCause().getMessage());
            }
        }
    }

    @Override
    public int getDatabaseMajorVersion() throws DatabaseException {
        if (databaseMajorVersion == null) {
            return super.getDatabaseMajorVersion();
        } else {
            return databaseMajorVersion;
        }
    }

    @Override
    public int getDatabaseMinorVersion() throws DatabaseException {
        if (databaseMinorVersion == null) {
            return super.getDatabaseMinorVersion();
        } else {
            return databaseMinorVersion;
        }
    }

    @Override
    public String getJdbcCatalogName(CatalogAndSchema schema) {
        return null;
    }

    @Override
    public String getJdbcSchemaName(CatalogAndSchema schema) {
        return correctObjectName((schema.getCatalogName() == null) ? schema.getSchemaName() : schema.getCatalogName(), Schema.class);
    }

    @Override
    protected String getAutoIncrementClause(final String generationType, final Boolean defaultOnNull) {
        if (StringUtil.isEmpty(generationType)) {
            return super.getAutoIncrementClause();
        }

        String autoIncrementClause = "GENERATED %s AS IDENTITY"; // %s -- [ ALWAYS | BY DEFAULT [ ON NULL ] ]
        String generationStrategy = generationType;
        if (Boolean.TRUE.equals(defaultOnNull) && generationType.toUpperCase().equals("BY DEFAULT")) {
            generationStrategy += " ON NULL";
        }
        return String.format(autoIncrementClause, generationStrategy);
    }

    @Override
    public String generatePrimaryKeyName(String tableName) {
        if (tableName.length() > 27) {
            //noinspection HardCodedStringLiteral
            return "PK_" + tableName.toUpperCase(Locale.US).substring(0, 27);
        } else {
            //noinspection HardCodedStringLiteral
            return "PK_" + tableName.toUpperCase(Locale.US);
        }
    }

    @Override
    public boolean isReservedWord(String objectName) {
        return reservedWords.contains(objectName.toUpperCase());
    }

    @Override
    public boolean supportsSequences() {
        return true;
    }

    /**
     * Oracle supports catalogs in liquibase terms
     *
     * @return false
     */
    @Override
    public boolean supportsSchemas() {
        return false;
    }

    @Override
    protected String getConnectionCatalogName() throws DatabaseException {
        if (getConnection() instanceof OfflineConnection) {
            return getConnection().getCatalog();
        }
        try {
            //noinspection HardCodedStringLiteral
            return Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForObject(new RawCallStatement("select sys_context( 'userenv', 'current_schema' ) from dual"), String.class);
        } catch (Exception e) {
            //noinspection HardCodedStringLiteral
            Scope.getCurrentScope().getLog(getClass()).info("Error getting default schema", e);
        }
        return null;
    }

    @Override
    public String getDefaultCatalogName() {//NOPMD
        return (super.getDefaultCatalogName() == null) ? null : super.getDefaultCatalogName().toUpperCase(Locale.US);
    }

    /**
     * 

Returns an Oracle date literal with the same value as a string formatted using ISO 8601.

* *

Convert an ISO8601 date string to one of the following results: * to_date('1995-05-23', 'YYYY-MM-DD') * to_date('1995-05-23 09:23:59', 'YYYY-MM-DD HH24:MI:SS')

*

* Implementation restriction:
* Currently, only the following subsets of ISO8601 are supported:
*

    *
  • YYYY-MM-DD
  • *
  • YYYY-MM-DDThh:mm:ss
  • *
*/ @Override public String getDateLiteral(String isoDate) { String normalLiteral = super.getDateLiteral(isoDate); if (isDateOnly(isoDate)) { return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD')"; } else if (isTimeOnly(isoDate)) { return "TO_DATE(" + normalLiteral + ", 'HH24:MI:SS')"; } else if (isTimestamp(isoDate)) { return "TO_TIMESTAMP(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS.FF')"; } else if (isDateTime(isoDate)) { int seppos = normalLiteral.lastIndexOf('.'); if (seppos != -1) { normalLiteral = normalLiteral.substring(0, seppos) + "'"; } return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS')"; } return "UNSUPPORTED:" + isoDate; } @Override public boolean isSystemObject(DatabaseObject example) { if (example == null) { return false; } if (this.isLiquibaseObject(example)) { return false; } if (example instanceof Schema) { //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral if ("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName())) { return true; } //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral if ("SYSTEM".equals(example.getSchema().getCatalogName()) || "SYS".equals(example.getSchema().getCatalogName()) || "CTXSYS".equals(example.getSchema().getCatalogName()) || "XDB".equals(example.getSchema().getCatalogName())) { return true; } } else if (isSystemObject(example.getSchema())) { return true; } if (example instanceof Catalog) { //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral if (("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName()))) { return true; } } else if (example.getName() != null) { //noinspection HardCodedStringLiteral if (example.getName().startsWith("BIN$")) { //oracle deleted table boolean filteredInOriginalQuery = this.canAccessDbaRecycleBin(); if (!filteredInOriginalQuery) { filteredInOriginalQuery = StringUtil.trimToEmpty(example.getSchema().getName()).equalsIgnoreCase(this.getConnection().getConnectionUserName()); } if (filteredInOriginalQuery) { return !((example instanceof PrimaryKey) || (example instanceof Index) || (example instanceof liquibase.statement.UniqueConstraint)); } else { return true; } } else //noinspection HardCodedStringLiteral if (example.getName().startsWith("AQ$")) { //oracle AQ tables return true; } else //noinspection HardCodedStringLiteral if (example.getName().startsWith("DR$")) { //oracle index tables return true; } else //noinspection HardCodedStringLiteral if (example.getName().startsWith("SYS_IOT_OVER")) { //oracle system table return true; } else //noinspection HardCodedStringLiteral,HardCodedStringLiteral if ((example.getName().startsWith("MDRT_") || example.getName().startsWith("MDRS_")) && example.getName().endsWith("$")) { // CORE-1768 - Oracle creates these for spatial indices and will remove them when the index is removed. return true; } else //noinspection HardCodedStringLiteral if (example.getName().startsWith("MLOG$_")) { //Created by materliaized view logs for every table that is part of a materialized view. Not available for DDL operations. return true; } else //noinspection HardCodedStringLiteral if (example.getName().startsWith("RUPD$_")) { //Created by materialized view log tables using primary keys. Not available for DDL operations. return true; } else //noinspection HardCodedStringLiteral if (example.getName().startsWith("WM$_")) { //Workspace Manager backup tables. return true; } else //noinspection HardCodedStringLiteral if ("CREATE$JAVA$LOB$TABLE".equals(example.getName())) { //This table contains the name of the Java object, the date it was loaded, and has a BLOB column to store the Java object. return true; } else //noinspection HardCodedStringLiteral if ("JAVA$CLASS$MD5$TABLE".equals(example.getName())) { //This is a hash table that tracks the loading of Java objects into a schema. return true; } else //noinspection HardCodedStringLiteral if (example.getName().startsWith("ISEQ$$_")) { //System-generated sequence return true; } else //noinspection HardCodedStringLiteral if (example.getName().startsWith("USLOG$")) { //for update materialized view return true; } else if (example.getName().startsWith("SYS_FBA")) { //for Flashback tables return true; } } return super.isSystemObject(example); } @Override public boolean supportsAutoIncrement() { // Oracle supports Identity beginning with version 12c boolean isAutoIncrementSupported = false; try { if (getDatabaseMajorVersion() >= 12) { isAutoIncrementSupported = true; } // Returning true will generate create table command with 'IDENTITY' clause, example: // CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) GENERATED BY DEFAULT AS IDENTITY NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey)); // While returning false will continue to generate create table command without 'IDENTITY' clause, example: // CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey)); } catch (DatabaseException ex) { isAutoIncrementSupported = false; } return isAutoIncrementSupported; }// public Set findUniqueConstraints(String schema) throws DatabaseException {// Set returnSet = new HashSet();//// List maps = new Executor(this).queryForList(new RawSqlStatement("SELECT UC.CONSTRAINT_NAME, UCC.TABLE_NAME, UCC.COLUMN_NAME FROM USER_CONSTRAINTS UC, USER_CONS_COLUMNS UCC WHERE UC.CONSTRAINT_NAME=UCC.CONSTRAINT_NAME AND CONSTRAINT_TYPE='U' ORDER BY UC.CONSTRAINT_NAME"));//// UniqueConstraint constraint = null;// for (Map map : maps) {// if (constraint == null || !constraint.getName().equals(constraint.getName())) {// returnSet.add(constraint);// Table table = new Table((String) map.get("TABLE_NAME"));// constraint = new UniqueConstraint(map.get("CONSTRAINT_NAME").toString(), table);// }// }// if (constraint != null) {// returnSet.add(constraint);// }//// return returnSet;// } @Override public boolean supportsRestrictForeignKeys() { return false; } @Override public int getDataTypeMaxParameters(String dataTypeName) { //noinspection HardCodedStringLiteral if ("BINARY_FLOAT".equals(dataTypeName.toUpperCase())) { return 0; } //noinspection HardCodedStringLiteral if ("BINARY_DOUBLE".equals(dataTypeName.toUpperCase())) { return 0; } return super.getDataTypeMaxParameters(dataTypeName); } public String getSystemTableWhereClause(String tableNameColumn) { List 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 '" + clauses.get(i) + "%'"); } return "(" + StringUtil.join(clauses, " AND ") + ")"; } @Override public boolean jdbcCallsCatalogsSchemas() { return true; } public Set getUserDefinedTypes() { if (userDefinedTypes == null) { userDefinedTypes = new HashSet(); if ((getConnection() != null) && !(getConnection() instanceof OfflineConnection)) { try { try { //noinspection HardCodedStringLiteral userDefinedTypes.addAll(Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForList(new RawSqlStatement("SELECT DISTINCT TYPE_NAME FROM ALL_TYPES"), String.class)); } catch (DatabaseException e) { //fall back to USER_TYPES if the user cannot see ALL_TYPES //noinspection HardCodedStringLiteral userDefinedTypes.addAll(Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForList(new RawSqlStatement("SELECT TYPE_NAME FROM USER_TYPES"), String.class)); } } catch (DatabaseException e) { //ignore error } } } return userDefinedTypes; } @Override public String generateDatabaseFunctionValue(DatabaseFunction databaseFunction) { //noinspection HardCodedStringLiteral if ((databaseFunction != null) && "current_timestamp".equalsIgnoreCase(databaseFunction.toString())) { return databaseFunction.toString(); } if ((databaseFunction instanceof SequenceNextValueFunction) || (databaseFunction instanceof SequenceCurrentValueFunction)) { String quotedSeq = super.generateDatabaseFunctionValue(databaseFunction); // replace "myschema.my_seq".nextval with "myschema"."my_seq".nextval return quotedSeq.replaceFirst("\"([^\\.\"]+)\\.([^\\.\"]+)\"", "\"$1\".\"$2\""); } return super.generateDatabaseFunctionValue(databaseFunction); } @Override public ValidationErrors validate() { ValidationErrors errors = super.validate(); DatabaseConnection connection = getConnection(); if ((connection == null) || (connection instanceof OfflineConnection)) { //noinspection HardCodedStringLiteral Scope.getCurrentScope().getLog(getClass()).info("Cannot validate offline database"); return errors; } if (!canAccessDbaRecycleBin()) { errors.addWarning(getDbaRecycleBinWarning()); } return errors; } public String getDbaRecycleBinWarning() { //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral, // HardCodedStringLiteral //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral 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" + "\n" + "The user you used to connect to the database (" + 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 " + getConnection().getConnectionUserName() + ";"; } public boolean canAccessDbaRecycleBin() { if (canAccessDbaRecycleBin == null) { DatabaseConnection connection = getConnection(); if ((connection == null) || (connection instanceof OfflineConnection)) { return false; } Statement statement = null; try { statement = ((JdbcConnection) connection).createStatement(); @SuppressWarnings("HardCodedStringLiteral") ResultSet resultSet = statement.executeQuery("select 1 from dba_recyclebin where 0=1"); resultSet.close(); //don't need to do anything with the result set, just make sure statement ran. this.canAccessDbaRecycleBin = true; } catch (Exception e) { //noinspection HardCodedStringLiteral if ((e instanceof SQLException) && e.getMessage().startsWith("ORA-00942")) { //ORA-00942: table or view does not exist this.canAccessDbaRecycleBin = false; } else { //noinspection HardCodedStringLiteral Scope.getCurrentScope().getLog(getClass()).warning("Cannot check dba_recyclebin access", e); this.canAccessDbaRecycleBin = false; } } finally { JdbcUtils.close(null, statement); } } return canAccessDbaRecycleBin; } @Override public boolean supportsNotNullConstraintNames() { return true; } /** * Tests if the given String would be a valid identifier in Oracle DBMS. In Oracle, a valid identifier has * the following form (case-insensitive comparison): * 1st character: A-Z * 2..n characters: A-Z0-9$_# * The maximum length of an identifier differs by Oracle version and object type. */ public boolean isValidOracleIdentifier(String identifier, Class type) { if ((identifier == null) || (identifier.length() < 1)) return false; if (!identifier.matches("^(i?)[A-Z][A-Z0-9\\$\\_\\#]*$")) return false; /* * @todo It seems we currently do not have a class for tablespace identifiers, and all other classes * we do know seem to be supported as 12cR2 long identifiers, so: */ return (identifier.length() <= LONG_IDENTIFIERS_LEGNTH); } /** * Returns the maximum number of bytes (NOT: characters) for an identifier. For Oracle <=12c Release 20, this * is 30 bytes, and starting from 12cR2, up to 128 (except for tablespaces, PDB names and some other rather rare * object types). * * @return the maximum length of an object identifier, in bytes */ public int getIdentifierMaximumLength() { try { if (getDatabaseMajorVersion() < ORACLE_12C_MAJOR_VERSION) { return SHORT_IDENTIFIERS_LENGTH; } else if ((getDatabaseMajorVersion() == ORACLE_12C_MAJOR_VERSION) && (getDatabaseMinorVersion() <= 1)) { return SHORT_IDENTIFIERS_LENGTH; } else { return LONG_IDENTIFIERS_LEGNTH; } } catch (DatabaseException ex) { throw new UnexpectedLiquibaseException("Cannot determine the Oracle database version number", ex); } }}

5.3 修改 liquibase.datatype.core.BooleanType类

同理复制源码,覆盖修改。

在toDatabaseDataType方法中添加DmDatabase的支持

在isNumericBoolean方法中添加DmDatabase类型

具体代码如下:可以直接复制

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package liquibase.datatype.core;

import java.util.Locale;

import liquibase.change.core.LoadDataChange;
import liquibase.change.core.LoadDataChange.LOAD_DATA_TYPE;
import liquibase.database.Database;
import liquibase.database.core.*;
import liquibase.datatype.DataTypeInfo;
import liquibase.datatype.DatabaseDataType;
import liquibase.datatype.LiquibaseDataType;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.statement.DatabaseFunction;
import liquibase.util.StringUtil;

@DataTypeInfo(
        name = "boolean",
        aliases = {"java.sql.Types.BOOLEAN", "java.lang.Boolean", "bit", "bool"},
        minParameters = 0,
        maxParameters = 0,
        priority = 1
)
public class BooleanType extends LiquibaseDataType {
    public BooleanType() {
    }

    @Override
    public DatabaseDataType toDatabaseDataType(Database database) {
        String originalDefinition = StringUtil.trimToEmpty(getRawDefinition());
        if ((database instanceof Firebird3Database)) {
            return new DatabaseDataType("BOOLEAN");
        }

        if ((database instanceof AbstractDb2Database) || (database instanceof FirebirdDatabase)) {
            return new DatabaseDataType("SMALLINT");
        } else if (database instanceof MSSQLDatabase) {
            return new DatabaseDataType(database.escapeDataTypeName("bit"));
        } else if (database instanceof MySQLDatabase) {
            if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) {
                return new DatabaseDataType("BIT", getParameters());
            }
            return new DatabaseDataType("BIT", 1);
        } else if (database instanceof OracleDatabase) {
            return new DatabaseDataType("NUMBER", 1);
        } else if ((database instanceof SybaseASADatabase) || (database instanceof SybaseDatabase)) {
            return new DatabaseDataType("BIT");
        } else if (database instanceof DerbyDatabase) {
            if (((DerbyDatabase) database).supportsBooleanDataType()) {
                return new DatabaseDataType("BOOLEAN");
            } else {
                return new DatabaseDataType("SMALLINT");
            }
        } else if (database.getClass().isAssignableFrom(DB2Database.class)) {
            if (((DB2Database) database).supportsBooleanDataType())
                return new DatabaseDataType("BOOLEAN");
            else
                return new DatabaseDataType("SMALLINT");
        } else if (database instanceof HsqlDatabase) {
            return new DatabaseDataType("BOOLEAN");
        } else if (database instanceof PostgresDatabase) {
            if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) {
                return new DatabaseDataType("BIT", getParameters());
            }
        } else if(database instanceof DmDatabase) {
            return new DatabaseDataType("bit");
        }

        return super.toDatabaseDataType(database);
    }

    @Override
    public String objectToSql(Object value, Database database) {
        if ((value == null) || "null".equals(value.toString().toLowerCase(Locale.US))) {
            return null;
        }

        String returnValue;
        if (value instanceof String) {
            value = ((String) value).replaceAll("'", "");
            if ("true".equals(((String) value).toLowerCase(Locale.US)) || "1".equals(value) || "b'1'".equals(((String) value).toLowerCase(Locale.US)) || "t".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getTrueBooleanValue(database).toLowerCase(Locale.US))) {
                returnValue = this.getTrueBooleanValue(database);
            } else if ("false".equals(((String) value).toLowerCase(Locale.US)) || "0".equals(value) || "b'0'".equals(
                    ((String) value).toLowerCase(Locale.US)) || "f".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getFalseBooleanValue(database).toLowerCase(Locale.US))) {
                returnValue = this.getFalseBooleanValue(database);
            } else {
                throw new UnexpectedLiquibaseException("Unknown boolean value: " + value);
            }
        } else if (value instanceof Long) {
            if (Long.valueOf(1).equals(value)) {
                returnValue = this.getTrueBooleanValue(database);
            } else {
                returnValue = this.getFalseBooleanValue(database);
            }
        } else if (value instanceof Number) {
            if (value.equals(1) || "1".equals(value.toString()) || "1.0".equals(value.toString())) {
                returnValue = this.getTrueBooleanValue(database);
            } else {
                returnValue = this.getFalseBooleanValue(database);
            }
        } else if (value instanceof DatabaseFunction) {
            return value.toString();
        } else if (value instanceof Boolean) {
            if (((Boolean) value)) {
                returnValue = this.getTrueBooleanValue(database);
            } else {
                returnValue = this.getFalseBooleanValue(database);
            }
        } else {
            throw new UnexpectedLiquibaseException("Cannot convert type " + value.getClass() + " to a boolean value");
        }

        return returnValue;
    }

    protected boolean isNumericBoolean(Database database) {
        if (database instanceof DerbyDatabase) {
            return !((DerbyDatabase) database).supportsBooleanDataType();
        } else if (database.getClass().isAssignableFrom(DB2Database.class)) {
            return !((DB2Database) database).supportsBooleanDataType();
        }
        return (database instanceof Db2zDatabase) || (database instanceof DB2Database) || (database instanceof FirebirdDatabase) || (database instanceof
                MSSQLDatabase) || (database instanceof MySQLDatabase) || (database instanceof OracleDatabase) ||
                (database instanceof SQLiteDatabase) || (database instanceof SybaseASADatabase) || (database instanceof
                SybaseDatabase) || (database instanceof DmDatabase);
    }

    /**
     * The database-specific value to use for "false" "boolean" columns.
     */
    public String getFalseBooleanValue(Database database) {
        if (isNumericBoolean(database)) {
            return "0";
        }
        if (database instanceof InformixDatabase) {
            return "'f'";
        }
        return "FALSE";
    }


    /**
     * The database-specific value to use for "true" "boolean" columns.
     */
    public String getTrueBooleanValue(Database database) {
        if (isNumericBoolean(database)) {
            return "1";
        }
        if (database instanceof InformixDatabase) {
            return "'t'";
        }
        return "TRUE";
    }


    @Override
    public LoadDataChange.LOAD_DATA_TYPE getLoadTypeName() {
        return LoadDataChange.LOAD_DATA_TYPE.BOOLEAN;
    }
}

5.4 修改resources/META-INF.services/liquibase.database.Database

添加DmDatabase支持。修改后的文件内如下,注意找不到源码的时候直接ctrl+shift+f 全局搜索即可。(也是在这个目录下建相同的文件,不能忘记,否者项目跑不起来!!!)

liquibase.database.core.CockroachDatabase
liquibase.database.core.DB2Database
liquibase.database.core.Db2zDatabase
liquibase.database.core.DerbyDatabase
liquibase.database.core.Firebird3Database
liquibase.database.core.FirebirdDatabase
liquibase.database.core.H2Database
liquibase.database.core.HsqlDatabase
liquibase.database.core.InformixDatabase
liquibase.database.core.Ingres9Database
liquibase.database.core.MSSQLDatabase
liquibase.database.core.MariaDBDatabase
liquibase.database.core.MockDatabase
liquibase.database.core.MySQLDatabase
liquibase.database.core.OracleDatabase
liquibase.database.core.PostgresDatabase
liquibase.database.core.SQLiteDatabase
liquibase.database.core.SybaseASADatabase
liquibase.database.core.SybaseDatabase
liquibase.database.core.DmDatabase
liquibase.database.core.UnsupportedDatabase

5.5 报错

00:04:55.338 [restartedMain] ERROR o.f.c.e.i.d.CommonDbSchemaManager – [getProperty,198] – Could not get property from table ACT_GE_PROPERTY

dm.jdbc.driver.DMException: 第1 行附近出现错误:

无效的表或视图名[ACT_GE_PROPERTY]

在网上找的报错解决方案

配置mysql连接时加上:nullCatalogMeansCurrent=true。最终配置如下

# 数据源配置
spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
#        driverClassName: com.mysql.cj.jdbc.Driver
        driverClassName: dm.jdbc.driver.DmDriver
        druid:
            # 主库数据源
#            master:
#                url: jdbc:mysql://121.43.234.114:3306/trading_center?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
#                username: root
#                password: gds12345678
             #主库数据源(本地mysql数据库)
#            master:
#                url: jdbc:mysql://localhost:3306/trading_center_dm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
#                username: root
#                password: 123
            # 主库数据源(本地达梦数据库)
            master:
                url: jdbc:dm://127.0.0.1:5236?TRADING_CENTER_DM&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true
                username: TRADING_CENTER_DM
                password: TRADING_CENTER_DM
            # 从库数据源
            slave:
                # 从数据源开关/默认关闭
                enabled: false
                url:
                username:
                password:
            # 初始连接数
            initialSize: 5
            # 最小连接池数量
            minIdle: 10
            # 最大连接池数量
            maxActive: 20
            # 配置获取连接等待超时的时间
            maxWait: 60000
            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
            timeBetweenEvictionRunsMillis: 60000
            # 配置一个连接在池中最小生存的时间,单位是毫秒
            minEvictableIdleTimeMillis: 300000
            # 配置一个连接在池中最大生存的时间,单位是毫秒
            maxEvictableIdleTimeMillis: 900000
            # 配置检测连接是否有效
            validationQuery: SELECT 1 FROM DUAL
            testWhileIdle: true
            testOnBorrow: false
            testOnReturn: false
            webStatFilter:
                enabled: true
            statViewServlet:
                enabled: true
                # 设置白名单,不填则允许所有访问
                allow:
                url-pattern: /druid/*
                # 控制台管理用户名和密码
                login-username: ruoyi
                login-password: 123456
            filter:
                stat:
                    enabled: true
                    # 慢SQL记录
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    merge-sql: true
                wall:
                    config:
                        multi-statement-allow: true

6、替换修改项目中的sql

mysql中的有些函数方式是达梦不支持的,所以要把部分sql替换为达梦支持的方式。(更多函数差别可以看官网文档或者本文章下面的附注)

本项目中主要修改的xml的sql如下

修改过sql的xml:

  • SysNoticeMapper.xml (case函数修改)
  • GenTableColumnMapper.xml (修改gen_table_column 表的插入语句的主键自增)
  • SysDeptMapper.xml (修改sys_dept 表的插入语句的主键自增)
  • SysJobMapper.xml (修改sys_job表的插入语句的主键自增)
  • SysJobLogMapper.xml(修改sys_job_log表的插入语句的主键自增)
  • SysMenuMapper.xml(修改sys_menu表的插入语句的主键自增)
  • SysPostMapper.xml(修改sys_post表的插入语句的主键自增)
  • SysUserMapper.xml(修改sys_user表的插入语句的主键自增)
  • SysJobLogMapper.xml(修改替换date_format 函数)
  • SysOperLogMapper.xml(修改替换date_format 函数)
  • GenTableColumnMapper.xml(代码生成的sql修改为达梦写法)

6.1 替换 find_in_set函数

由于达梦数据库没有内置find_in_set函数,但项目中有用到,所以需要自定义函数,方便后续程序调用。

先切换模式

set schema TRADING_CENTER_DM;

再创建函数FIND_IN_SET

CREATE OR REPLACE FUNCTION FIND_IN_SET
                (
                        piv_str1 varchar2,
                        piv_str2 varchar2,
                        p_sep    varchar2 := ',')
                RETURN NUMBER
                            IS
                l_idx     number:=0;                 -- 用于计算piv_str2中分隔符的位置
                str       varchar2(500);             -- 根据分隔符截取的子字符串
                piv_str   varchar2(500) := piv_str2; -- 将piv_str2赋值给piv_str
                res       number        :=0;         -- 返回结果
                loopIndex number        :=0;
        BEGIN
                -- 如果piv_str中没有分割符,直接判断piv_str1和piv_str是否相等,相等 res=1
                IF instr(piv_str, p_sep, 1) = 0 THEN
                        IF piv_str          = piv_str1 THEN
                                res        := 1;
                        END IF;
                ELSE
                        -- 循环按分隔符截取piv_str
                        LOOP
                                l_idx    := instr(piv_str, p_sep);
                                loopIndex:=loopIndex+1;
                                -- 当piv_str中还有分隔符时
                                IF l_idx > 0 THEN
                                        -- 截取第一个分隔符前的字段str
                                        str:= substr(piv_str, 1, l_idx-1);
                                        -- 判断 str 和piv_str1 是否相等,相等 res=1 并结束循环判断
                                        IF str      = piv_str1 THEN
                                                res:= loopIndex;
                                                EXIT;
                                        END IF;
                                        piv_str := substr(piv_str, l_idx+length(p_sep));
                                ELSE
                                        -- 当截取后的piv_str 中不存在分割符时,判断piv_str和piv_str1是否相等,相等 res=1
                                        IF piv_str  = piv_str1 THEN
                                                res:= loopIndex;
                                        END IF;
                                        -- 无论最后是否相等,都跳出循环
                                        EXIT;
                                END IF;
                        END LOOP;
                        -- 结束循环
                END IF;
                -- 返回res
                RETURN res;
        END FIND_IN_SET;
commit;

6.2 替换case()函数

cast(),mysq有,达梦没有。

cast(xxx as SIGNED INTEGER) -- mysql函数

替换为

to_number(xxx) -- 达梦函数

cast(notice_content as char)  --mysql函数 notice_content是longblob类型 转为了char
替换为
CONVERT(notice_content, SQL_CHAR)  --达梦函数 notice_content是blob类型 转为了char

6.3 根据达梦的主键自增修改SQL

达梦的主键自增是不允许INSERT INTO语句中出现那个字段名的。就算赋值为null也会报错。

错误

INSERT INTO sys_logs_method ( Id, ActionTime, ActionBy, Type, IsDelete, Remark, Ip, ActionByName, ProjectNo, actionByAccount ) VALUES ( 0, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 

错误

INSERT INTO sys_logs_method ( Id, ActionTime, ActionBy, Type, IsDelete, Remark, Ip, ActionByName, ProjectNo, actionByAccount ) VALUES ( null, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 

正确

INSERT INTO sys_logs_method ( ActionTime, ActionBy, Type, IsDelete, Remark, Ip, ActionByName, ProjectNo, actionByAccount ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? ) 

修改过xml语句的详细情况见 目录6。

6.4 修改替换date_format 函数

达梦不支持 date_sub 函数,使用 dateadd(datepart,n,date) 代替,其中,datepart可以为:year(yy,yyyy),quarter(qq,q),month(mm,m),dayofyear(dy,y),day(dd,d),week(wk,ww),weekday(dw),hour(hh), minute(mi,n), second(ss,s), millisecond(ms),

select dateadd(month, -6, now());  --dameng
select dateadd(month, 2, now());   --dameng

替换例子:

 date_format(create_time,'%y%m%d')   --mysql
 替换为达梦
to_char(create_time, 'YYMMDD')       --dameng

6.5 不支持 case-when-then-else

不支持 case-when-then-else

这里有一个若依框架中代码生成的case—when的例子

mysql写法

    
		select column_name, (case when (is_nullable = 'no'  column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
		from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
		order by ordinal_position
	

改达梦

    select t3.COLUMN_NAME                     as column_name,
           (CASE
                WHEN (t3.NULLABLE = 'N' and t4.CONSTRAINT_TYPE !='P') THEN '1'
                ELSE NULL END)
                                              as is_required,
           IF(t4.CONSTRAINT_TYPE = 'P', 1, 0) as is_pk,
           t3.COLUMN_ID                       as sort,
           t5.COMMENTS                        as column_comment,
           (  CASE
                  WHEN (t3.TYPE = 'INT' OR t3.TYPE = 'INTEGER' OR t3.TYPE = 'BIGINT' OR t3.TYPE = 'TINYINT' OR
                        t3.TYPE = 'SMALLINT') and t4.CONSTRAINT_TYPE = 'P' THEN '1'
                  ELSE '0' END  )                 AS is_increment,
           DATA_TYPE as DATA_TYPE
    from ((select COLUMN_NAME,
                  COLUMN_ID,
                  concat(DATA_TYPE, '(', DATA_LENGTH, ')') as DATA_TYPE,
                  DATA_TYPE                                as TYPE,
                  TABLE_NAME,
                  NULLABLE
           from SYS.USER_TAB_COLUMNS
           WHERE table_name = (#{tableName})) t3
             left join (select COMMENTS, COLUMN_NAME, TABLE_NAME from SYS.USER_COL_COMMENTS) t5
                       ON (t3.COLUMN_NAME = t5.COLUMN_NAME and t3.TABLE_NAME = t5.TABLE_NAME)
             left join
         (select t1.CONSTRAINT_TYPE, t1.OWNER, t1.TABLE_NAME, t2.CONSTRAINT_NAME, t2.COLUMN_NAME
          from (select CONSTRAINT_NAME, CONSTRAINT_TYPE, OWNER, TABLE_NAME from SYS.USER_CONSTRAINTS) t1
                   inner join (select CONSTRAINT_NAME, OWNER, TABLE_NAME, COLUMN_NAME from SYS.USER_CONS_COLUMNS) t2
                              ON (t1.TABLE_NAME = t2.TABLE_NAME and t1.CONSTRAINT_NAME = t2.CONSTRAINT_NAME)
          where t1.CONSTRAINT_TYPE = 'P') t4 ON (t3.COLUMN_NAME = t4.COLUMN_NAME and t3.TABLE_NAME = t4.TABLE_NAME))
    order by t3.COLUMN_ID

若依框架的代码生成还有几个xml的方法也需要替换,如下:

  
        select t1.TABLE_NAME as table_name, t2.COMMENTS as table_comment, NULL as create_time, NULL as update_time
        from SYS.USER_TABLES t1
        inner join SYS.USER_TAB_COMMENTS t2 ON t1.TABLE_NAME = t2.TABLE_NAME
        WHERE t1.TABLE_NAME NOT LIKE 'qrtz_%'
        AND t1.TABLE_NAME NOT LIKE 'gen_%'
        AND t1.TABLE_NAME NOT IN (select table_name as TABLE_NAME from gen_table)
        
            AND lower(t1.TABLE_NAME) like lower(concat('%', #{tableName}, '%'))
        
        
            AND lower(t1.TABLE_NAME) like lower(concat('%', #{tableName}, '%'))
        
    

 
        select t1.TABLE_NAME as table_name, t2.COMMENTS as table_comment, NULL as create_time, NULL as update_time
        from SYS.USER_TABLES t1
        inner join SYS.USER_TAB_COMMENTS t2 ON t1.TABLE_NAME = t2.TABLE_NAME
        WHERE t1.TABLE_NAME NOT LIKE 'qrtz_%'
        AND t1.TABLE_NAME NOT LIKE 'gen_%'
        and t1.TABLE_NAME in
        
            #{name}
        
    
                                                       

    select t1.TABLE_NAME as table_name, t2.COMMENTS as table_comment, NULL as create_time, NULL as update_time
    from SYS.USER_TABLES t1
             inner join SYS.USER_TAB_COMMENTS t2 ON t1.TABLE_NAME = t2.TABLE_NAME
    where t2.COMMENTS <![CDATA[  ]]> ''
      and t1.TABLE_NAME = #{tableName}
                                         

7 、附注

7.1 源码的修改方式

根据源文件路径,在java包下新建java class文件,将源文件中代码粘贴到新创建的文件中,修改相关代码后保存,编译。

若依以及flowbale达梦国产化数据库改造

在target中找到编译后的class文件

若依以及flowbale达梦国产化数据库改造

找对源文件所在jar包,右键在文件管理中打开。

若依以及flowbale达梦国产化数据库改造

解压jar包,将修改后并编译的target中的class文件粘贴到jar包对应位置,然后重新打包成zip压缩包后修改后缀为.jar

批注:jar包中的源码修改后能用git提交吗

当你修改了一个 JAR 包中的源码后,你实际上修改了该 JAR 包的一个副本。这个修改并不会影响到原始的 JAR 包,因此无法直接使用 Git 提交这些修改。

7.2 启动Maven项目 程序包不存在报错

如果依赖什么都没问题的话这个一般就是项目编译问题,把项目重新编译

点击Maven中的 M 按钮,然后输入下面的命令 把项目重新编译就可以运行了

mvn idea:idea

若依以及flowbale达梦国产化数据库改造

若依以及flowbale达梦国产化数据库改造

7.3 mysql与达梦的部分sql函数差异

这里只提供常见的差异,详情还得根据改造后的功能进行测试,或者参考官方文档。

(1)创建表的时候,不支持在列的后面直接加comment注释,使用 COMMENT ON IS 代替,如:

COMMENT ON TABLE xxx IS xxx
COMMENT ON COLUMN xxx IS xxx

(2)不支持 date_sub 函数,使用 dateadd(datepart,n,date) 代替,其中,datepart可以为:year(yy,yyyy),quarter(qq,q),month(mm,m),dayofyear(dy,y),day(dd,d),week(wk,ww),weekday(dw),hour(hh), minute(mi,n), second(ss,s), millisecond(ms),例子:

select dateadd(month, -6, now());
select dateadd(month, 2, now());

(3)不支持 date_format 函数,它有三种代替方法:

A: 使用 datepart 代替:语法:datepart(datepart, date),返回代表日期的指定部分的整数,datepart可以为:year(yy,yyyy),quarter(qq,q),month(mm,m),dayofyear(dy,y),day(dd,d),week(wk,ww),weekday(dw),hour(hh), minute(mi,n),second(ss,s), millisecond(ms),例子:

select datepart(year, '2023-04-13 08:45:00'); --2023
select datepart(month, '2022-12-13 08:45:00'); --12

B: 使用 date_part 代替,功能和 datepart 一样,写法不同,参数顺序颠倒,且都要加引号,例子:

select date_part('2023-12-13 08:45:00', 'year');--2023
select date_part('2022-12-13 08:45:00', 'mm'); -- 12

C: 使用 extract 代替,语法:extract(dtfield from date),从日期类型date中抽取dtfield对应的值,dtfield 可以是 year,month,day,hour,minute,second,例子:

select extract(year from  '2023-12-13 08:45:00'); --2023
select extract(month from  '2022-12-13 08:45:00'); --12

(4)不支持 substring_index 函数, 使用 substr / substring 代替,语法:

substr(char[,m[,n]])
substring(char[from m[ for n]])

(5)不支持 group_concat 函数,使用 wm_concat 代替,例子:

select wm_concat(id) as idstr from persion ORDER BY id ;

(6)不支持 from_unixtime 函数,使用 round 代替,语法:

round(date[,format])

(7)不支持 case-when-then-else ,例如:

select case  when id = 2 then "aaa" when id = 3 then "bbb" else "ccc" end as test from (select id from person) tt;

(8)current_timestamp 的返回值带有时区,例子:

select current_timestamp();
2023-04-37 14:34:18.433839 +08:00

r(yy,yyyy),quarter(qq,q),month(mm,m),dayofyear(dy,y),day(dd,d),week(wk,ww),weekday(dw),hour(hh), minute(mi,n), second(ss,s), millisecond(ms),例子:

select dateadd(month, -6, now());
select dateadd(month, 2, now());

(3)不支持 date_format 函数,它有三种代替方法:

A: 使用 datepart 代替:语法:datepart(datepart, date),返回代表日期的指定部分的整数,datepart可以为:year(yy,yyyy),quarter(qq,q),month(mm,m),dayofyear(dy,y),day(dd,d),week(wk,ww),weekday(dw),hour(hh), minute(mi,n),second(ss,s), millisecond(ms),例子:

select datepart(year, '2023-04-13 08:45:00'); --2023
select datepart(month, '2022-12-13 08:45:00'); --12

B: 使用 date_part 代替,功能和 datepart 一样,写法不同,参数顺序颠倒,且都要加引号,例子:

select date_part('2023-12-13 08:45:00', 'year');--2023
select date_part('2022-12-13 08:45:00', 'mm'); -- 12

C: 使用 extract 代替,语法:extract(dtfield from date),从日期类型date中抽取dtfield对应的值,dtfield 可以是 year,month,day,hour,minute,second,例子:

select extract(year from  '2023-12-13 08:45:00'); --2023
select extract(month from  '2022-12-13 08:45:00'); --12

(4)不支持 substring_index 函数, 使用 substr / substring 代替,语法:

substr(char[,m[,n]])
substring(char[from m[ for n]])

(5)不支持 group_concat 函数,使用 wm_concat 代替,例子:

select wm_concat(id) as idstr from persion ORDER BY id ;

(6)不支持 from_unixtime 函数,使用 round 代替,语法:

round(date[,format])

(7)不支持 case-when-then-else ,例如:

select case  when id = 2 then "aaa" when id = 3 then "bbb" else "ccc" end as test from (select id from person) tt;

(8)current_timestamp 的返回值带有时区,例子:

select current_timestamp();
2023-04-37 14:34:18.433839 +08:00

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/0d634c8609.html