liquibase扩展支持达梦数据库

近期项目中需要支持国产数据库,需要liquibase底层支持达梦数据库,记录下操作的详细步骤以便分享。
1.liquibase支持的数据库很多如MySQL, PostgreSQL, Oracle, Sql Server, DB2。但是达梦数据库并不支持,所以需要新建DMDatabase类来适配达梦数据库。达梦语法和Oracle很像所以只需要复制liquibase-core下的Oracle Database做些修改就可了。以下为需要修改的地方

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

    @Override
    public String getShortName() {
        //noinspection HardCodedStringLiteral
        return "dm";
    }

    @Override
    protected String getDefaultDatabaseProductName() {
        //noinspection HardCodedStringLiteral
        return PRODUCT_NAME;
    }
    
    @Override
    public Integer getDefaultPort() {
        return 5236;
    }
    
    @Override
    public String getDefaultDriver(String url) {
        //noinspection HardCodedStringLiteral
        if (url.startsWith("jdbc:dm")) {
            return "dm.jdbc.driver.DmDriver";
        }
        return null;
    }
}

2.达梦不支持booelan类型需要转为int,所以需要修改Boolean类,修改地方为://支持达梦自增列

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

    @Override
    public DatabaseDataType toDatabaseDataType(Database database) {
        String originalDefinition = StringUtils.trimToEmpty(getRawDefinition());
        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 instanceof HsqlDatabase) {
            return new DatabaseDataType("BOOLEAN");
        } else if (database instanceof PostgresDatabase) {
            if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) {
                return new DatabaseDataType("BIT", getParameters());
            }
    }//转int
    else if (database instanceof DMDatabase){
            return new DatabaseDataType("INT");
        }

        return super.toDatabaseDataType(database);
    }

    protected boolean isNumericBoolean(Database database) {
        if (database instanceof DerbyDatabase) {
            return !((DerbyDatabase) database).supportsBooleanDataType();
        }
        return (database instanceof AbstractDb2Database) || (database instanceof FirebirdDatabase) || (database instanceof
            MSSQLDatabase) || (database instanceof MySQLDatabase) || (database instanceof OracleDatabase) ||
            (database instanceof SQLiteDatabase) || (database instanceof SybaseASADatabase) || (database instanceof
            SybaseDatabase) || (database instanceof DMDatabase);
    }
}
  1. 达梦的自增列语法与其他不同需要修改CreateTableGenerator类
    @Override
    public Sql[] generateSql(CreateTableStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {

        List<Sql> additionalSql = new ArrayList<>();

        StringBuffer buffer = new StringBuffer();
        buffer.append("CREATE TABLE ").append(database.escapeTableName(statement.getCatalogName(),
            statement.getSchemaName(), statement.getTableName())).append(" ");
        buffer.append("(");

        boolean isSinglePrimaryKeyColumn = (statement.getPrimaryKeyConstraint() != null) && (statement
            .getPrimaryKeyConstraint().getColumns().size() == 1);

        boolean isPrimaryKeyAutoIncrement = false;

        Iterator<String> columnIterator = statement.getColumns().iterator();

        BigInteger mysqlTableOptionStartWith = null;

        /* We have reached the point after "CREATE TABLE ... (" and will now iterate through the column list. */
        while (columnIterator.hasNext()) {
            String column = columnIterator.next();
            DatabaseDataType columnType = statement.getColumnTypes().get(column).toDatabaseDataType(database);
            buffer.append(database.escapeColumnName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), column, true));

            buffer.append(" ").append(columnType);

            AutoIncrementConstraint autoIncrementConstraint = null;

            for (AutoIncrementConstraint currentAutoIncrementConstraint : statement.getAutoIncrementConstraints()) {
                if (column.equals(currentAutoIncrementConstraint.getColumnName())) {
                    autoIncrementConstraint = currentAutoIncrementConstraint;
                    break;
                }
            }

            boolean isAutoIncrementColumn = autoIncrementConstraint != null;
            boolean isPrimaryKeyColumn = (statement.getPrimaryKeyConstraint() != null) && statement
                .getPrimaryKeyConstraint().getColumns().contains(column);
            isPrimaryKeyAutoIncrement = isPrimaryKeyAutoIncrement || (isPrimaryKeyColumn && isAutoIncrementColumn);

            if ((database instanceof SQLiteDatabase) &&
                    isSinglePrimaryKeyColumn &&
                    isPrimaryKeyColumn &&
                    isAutoIncrementColumn) {
                String pkName = StringUtils.trimToNull(statement.getPrimaryKeyConstraint().getConstraintName());
                if (pkName == null) {
                    pkName = database.generatePrimaryKeyName(statement.getTableName());
                }
                if (pkName != null) {
                    buffer.append(" CONSTRAINT ");
                    buffer.append(database.escapeConstraintName(pkName));
                }
                buffer.append(" PRIMARY KEY");
            }

            // for the serial data type in postgres, there should be no default value
            if (!columnType.isAutoIncrement() && (statement.getDefaultValue(column) != null)) {
                Object defaultValue = statement.getDefaultValue(column);
                if (database instanceof MSSQLDatabase) {
                    String constraintName = statement.getDefaultValueConstraintName(column);
                    if (constraintName == null) {
                        constraintName = ((MSSQLDatabase) database).generateDefaultConstraintName(statement.getTableName(), column);
                    }
                    buffer.append(" CONSTRAINT ").append(database.escapeObjectName(constraintName, ForeignKey.class));
                }
                if ((database instanceof OracleDatabase) && statement.getDefaultValue(column).toString().startsWith
                    ("GENERATED ALWAYS ")) {
                    buffer.append(" ");
                } else if (database instanceof Db2zDatabase && statement.getDefaultValue(column).toString().contains("CURRENT TIMESTAMP")
                        || statement.getDefaultValue(column).toString().contains("IDENTITY GENERATED BY DEFAULT")) {
                    buffer.append(" ");
                } else {
                    buffer.append(" DEFAULT ");
                }

                if (defaultValue instanceof DatabaseFunction) {
                    buffer.append(database.generateDatabaseFunctionValue((DatabaseFunction) defaultValue));
                } else if (database instanceof Db2zDatabase) {
                    if (statement.getDefaultValue(column).toString().contains("CURRENT TIMESTAMP")) {
                        buffer.append("");
                    }
                    if (statement.getDefaultValue(column).toString().contains("IDENTITY GENERATED BY DEFAULT")) {
                        buffer.append("GENERATED BY DEFAULT AS IDENTITY");
                    }
                    if (statement.getDefaultValue(column).toString().contains("CURRENT USER")) {
                        buffer.append("SESSION_USER ");
                    }
                    if (statement.getDefaultValue(column).toString().contains("CURRENT SQLID")) {
                        buffer.append("CURRENT SQLID ");
                    }
                } else {
                    buffer.append(statement.getColumnTypes().get(column).objectToSql(defaultValue, database));
                }
            }

            if (isAutoIncrementColumn) {
                // TODO: check if database supports auto increment on non primary key column
                if (database.supportsAutoIncrement()) {
                    String autoIncrementClause = database.getAutoIncrementClause(autoIncrementConstraint.getStartWith(), autoIncrementConstraint.getIncrementBy());

                    if (!"".equals(autoIncrementClause)) {
                        buffer.append(" ").append(autoIncrementClause);
                    }

                    if( autoIncrementConstraint.getStartWith() != null ){
                        if (database instanceof PostgresDatabase) {
                            String sequenceName = statement.getTableName()+"_"+column+"_seq";
                            additionalSql.add(new UnparsedSql("alter sequence "+database.escapeSequenceName(statement.getCatalogName(), statement.getSchemaName(), sequenceName)+" start with "+autoIncrementConstraint.getStartWith(), new Sequence().setName(sequenceName).setSchema(statement.getCatalogName(), statement.getSchemaName())));
                        }else if(database instanceof MySQLDatabase){
                            mysqlTableOptionStartWith = autoIncrementConstraint.getStartWith();
                        }
                    }
                }
                //支持达梦自增列
                else if(isAutoIncrementColumn && database instanceof DMDatabase){
                     buffer.append(" identity(1,1)");
                }
                else {
                    LogService.getLog(getClass()).warning(LogType.LOG, database.getShortName()+" does not support autoincrement columns as requested for "+(database.escapeTableName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName())));
                }
            }

            // Do we have a NOT NULL constraint for this column?
            if (statement.getNotNullColumns().get(column) != null) {
                if (! database.supportsNotNullConstraintNames()) {
                    buffer.append(" NOT NULL");
                } else {
                    /* Determine if the NOT NULL constraint has a name. */
                    NotNullConstraint nnConstraintForThisColumn = statement.getNotNullColumns().get(column);
                    String nncName = StringUtils.trimToNull(nnConstraintForThisColumn.getName());
                    if (nncName == null) {
                        buffer.append(" NOT NULL");
                    } else {
                        buffer.append(" CONSTRAINT ");
                        buffer.append(database.escapeConstraintName(nncName));
                        buffer.append(" NOT NULL");
                    } // do we have a NN constraint name?
                } // does the DB support constraint names?
            } else {
                if ((database instanceof SybaseDatabase) || (database instanceof SybaseASADatabase) || (database
                    instanceof MySQLDatabase) || ((database instanceof MSSQLDatabase) && columnType.toString()
                    .toLowerCase().contains("timestamp"))) {
                    buffer.append(" NULL");
                } // Do we need to specify NULL explicitly?
            } // Do we have a NOT NULL constraint for this column?

            if ((database instanceof MySQLDatabase) && (statement.getColumnRemarks(column) != null)) {
                buffer.append(" COMMENT '" + database.escapeStringForDatabase(statement.getColumnRemarks(column)) + "'");
            }

            if (columnIterator.hasNext()) {
                buffer.append(", ");
            }
        }

        buffer.append(",");

        if (!( (database instanceof SQLiteDatabase) &&
                isSinglePrimaryKeyColumn &&
                isPrimaryKeyAutoIncrement) ) {

            if ((statement.getPrimaryKeyConstraint() != null) && !statement.getPrimaryKeyConstraint().getColumns()
                .isEmpty()) {
                if (database.supportsPrimaryKeyNames()) {
                    String pkName = StringUtils.trimToNull(statement.getPrimaryKeyConstraint().getConstraintName());
                    if (pkName == null) {
                        // TODO ORA-00972: identifier is too long
                        // If tableName lenght is more then 28 symbols
                        // then generated pkName will be incorrect
                        pkName = database.generatePrimaryKeyName(statement.getTableName());
                    }
                    if (pkName != null) {
                        buffer.append(" CONSTRAINT ");
                        buffer.append(database.escapeConstraintName(pkName));
                    }
                }
                buffer.append(" PRIMARY KEY (");
                buffer.append(database.escapeColumnNameList(StringUtils.join(statement.getPrimaryKeyConstraint().getColumns(), ", ")));
                buffer.append(")");
                // Setting up table space for PK's index if it exist
                if (((database instanceof OracleDatabase) || (database instanceof PostgresDatabase)) && (statement
                    .getPrimaryKeyConstraint().getTablespace() != null)) {
                    buffer.append(" USING INDEX TABLESPACE ");
                    buffer.append(statement.getPrimaryKeyConstraint().getTablespace());
                }

                buffer.append(",");
            }
        }

        for (ForeignKeyConstraint fkConstraint : statement.getForeignKeyConstraints()) {
            if (!(database instanceof InformixDatabase)) {
                buffer.append(" CONSTRAINT ");
                buffer.append(database.escapeConstraintName(fkConstraint.getForeignKeyName()));
            }
            String referencesString = fkConstraint.getReferences();

            buffer.append(" FOREIGN KEY (")
                    .append(database.escapeColumnName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), fkConstraint.getColumn()))
                    .append(") REFERENCES ");
            if (referencesString != null) {
                if (!referencesString.contains(".") && (database.getDefaultSchemaName() != null) && database
                    .getOutputDefaultSchema()) {
                    referencesString = database.escapeObjectName(database.getDefaultSchemaName(), Schema.class) +"."+referencesString;
                }
                buffer.append(referencesString);
            } else {
                buffer.append(database.escapeObjectName(fkConstraint.getReferencedTableCatalogName(), fkConstraint.getReferencedTableSchemaName(), fkConstraint.getReferencedTableName(), Table.class))
                    .append("(")
                    .append(database.escapeColumnNameList(fkConstraint.getReferencedColumnNames()))
                    .append(")");

            }


            if (fkConstraint.isDeleteCascade()) {
                buffer.append(" ON DELETE CASCADE");
            }

            if ((database instanceof InformixDatabase)) {
                buffer.append(" CONSTRAINT ");
                buffer.append(database.escapeConstraintName(fkConstraint.getForeignKeyName()));
            }

            if (fkConstraint.isInitiallyDeferred()) {
                buffer.append(" INITIALLY DEFERRED");
            }
            if (fkConstraint.isDeferrable()) {
                buffer.append(" DEFERRABLE");
            }
            buffer.append(",");
        }

        for (UniqueConstraint uniqueConstraint : statement.getUniqueConstraints()) {
            if (uniqueConstraint.getConstraintName() != null) {
                buffer.append(" CONSTRAINT ");
                buffer.append(database.escapeConstraintName(uniqueConstraint.getConstraintName()));
            }
            buffer.append(" UNIQUE (");
            buffer.append(database.escapeColumnNameList(StringUtils.join(uniqueConstraint.getColumns(), ", ")));
            buffer.append(")");
            buffer.append(",");
        }

        /*
         * Here, the list of columns and constraints in the form
         * ( column1, ..., columnN, constraint1, ..., constraintN,
         * ends. We cannot leave an expression like ", )", so we remove the last comma.
         */
        String sql = buffer.toString().replaceFirst(",\\s*$", "")+")";

        if ((database instanceof MySQLDatabase) && (mysqlTableOptionStartWith != null)){
            LogService.getLog(getClass()).info(LogType.LOG, "[MySQL] Using last startWith statement ("+mysqlTableOptionStartWith.toString()+") as table option.");
            sql += " "+((MySQLDatabase)database).getTableOptionAutoIncrementStartWithClause(mysqlTableOptionStartWith);
        }

        if ((statement.getTablespace() != null) && database.supportsTablespaces()) {
            if ((database instanceof MSSQLDatabase) || (database instanceof SybaseASADatabase)) {
                sql += " ON " + statement.getTablespace();
            } else if ((database instanceof AbstractDb2Database) || (database instanceof InformixDatabase)) {
                sql += " IN " + statement.getTablespace();
            } else {
                sql += " TABLESPACE " + statement.getTablespace();
            }
        }

        if((database instanceof MySQLDatabase) && (statement.getRemarks() != null)) {
            sql += " COMMENT='"+database.escapeStringForDatabase(statement.getRemarks())+"' ";
        }
        additionalSql.add(0, new UnparsedSql(sql, getAffectedTable(statement)));
        return additionalSql.toArray(new Sql[additionalSql.size()]);
    }

4.达梦不支持liquibase xm中的loadData标签需要做适配修改ModifyDataTypeGenerator类

    protected String getModifyString(Database database) {
        if ((database instanceof SybaseASADatabase) || (database instanceof SybaseDatabase) || (database instanceof
            MySQLDatabase) || (database instanceof OracleDatabase) || (database instanceof InformixDatabase) || (database instanceof DMDatabase)
                ) {
            return "MODIFY";
        } else {
            return "ALTER COLUMN";
        }
    }

    protected String getPreDataTypeString(Database database) {
        if ((database instanceof DerbyDatabase) || (database instanceof AbstractDb2Database)) {
            return " SET DATA TYPE ";
        } else if ((database instanceof SybaseASADatabase) || (database instanceof SybaseDatabase) || (database
            instanceof MSSQLDatabase) || (database instanceof MySQLDatabase) || (database instanceof HsqlDatabase) ||
            (database instanceof H2Database) || (database instanceof OracleDatabase) || (database instanceof
            InformixDatabase) || (database instanceof DMDatabase )) {
            return " ";
        } else {
            return " TYPE ";
        }
    }

关于达梦数据库的问题可以去达梦社区提问https://eco.dameng.com/community/question/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Liquibase 管理 H2 数据库需要以下步骤: 1. 首先,需要在项目中添加 H2 数据库Liquibase支持。可以使用 Maven 或 Gradle 等构建工具来添加这些依赖项。 2. 然后,在项目中创建一个 Liquibase 的配置文件,例如 `liquibase.properties` 或者 `liquibase.yml`,并指定数据库连接信息、change log 文件等相关信息。 3. 在 `change log` 文件中,可以使用 Liquibase 的语法来定义数据库的 schema 和数据。例如,可以使用 `createTable` 来创建表,使用 `addColumn` 来添加列,使用 `insert` 来插入数据等。 4. 最后,在项目启动时,可以使用 Liquibase 的 API 来执行 change log 文件,并更新数据库的 schema 和数据。可以通过命令行或者 Java 代码来执行 Liquibase。 下面是一个示例 `liquibase.properties` 文件的内容: ``` driver: org.h2.Driver classpath: path/to/h2.jar url: jdbc:h2:mem:test username: sa password: changeLogFile: path/to/changelog.xml ``` 其中,`driver`、`classpath`、`url`、`username`、`password` 分别指定了数据库连接信息,`changeLogFile` 指定了 change log 文件的位置。 下面是一个示例 `changelog.xml` 文件的内容: ```xml <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd"> <changeSet id="1" author="me"> <createTable tableName="person"> <column name="id" type="INT"> <constraints primaryKey="true" nullable="false"/> </column> <column name="name" type="VARCHAR(50)"> <constraints nullable="false"/> </column> <column name="age" type="INT"> <constraints nullable="true"/> </column> </createTable> </changeSet> <changeSet id="2" author="me"> <insert tableName="person"> <column name="id" value="1"/> <column name="name" value="John"/> <column name="age" value="30"/> </insert> <insert tableName="person"> <column name="id" value="2"/> <column name="name" value="Jane"/> <column name="age" value="25"/> </insert> </changeSet> </databaseChangeLog> ``` 其中,`changeSet` 标签用于表示一个变更集,`createTable` 标签用于创建表,`insert` 标签用于插入数据。 使用 Liquibase 可以方便地管理 H2 数据库的 schema 和数据,同时也可以兼容其他数据库。在实际开发中,可以根据具体需求来使用 Liquibase 的不同功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值