1 Star 5 Fork 1

雨过天晴 / liquibase-go

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
BSD-2-Clause

liquigo: Liquibase by golang

liquigo是一个参考Liquibase中间件的golang开发的数据库版本管理工具,实现了大多数以xml格式配置的常用语法,支持的数据库类型和语法参见如下表格:

Liquibase语法(仅支持xml格式) MySQL / TiDB / OceanBase MariaDB openGauss / PostgreSQL KingbaseES 达梦 SQLite Oracle SQL Server
变更集:changeSet
变更集注释:comment
创建表:createTable
删除表:dropTable
重命名表:renameTable -
添加列:addColumn -
删除列:dropColumn
重命名列:renameColumn -
变更列:modifyDataType -
删除默认值:dropDefaultValue -
创建视图:createView
删除视图:dropView
创建索引:createIndex
删除索引:dropIndex
属性替换${}
执行SQL语句:sql
执行SQL文件:sqlFile
前置条件:preConditions
前置条件与或非:not,and,or
前置条件存在判断:tableExists,viewExists
前置条件存在判断:columnExists,sqlCheck
前置条件存在判断:indexExists ×
事务回滚:rollback
开发调试用停止:stop

测试过的数据库系统版本有:

openGauss V2.1.0 (兼容PostgreSQL模式)

OceanBase V3.1.1 (兼容MySQL模式)

MySQL V5.7.27 / MySQL V8.0.28

TiDB V5.4.0

MariaDB V10.3.34

PostgreSQL V12.10

KingbaseES V008R006

达梦 V8.1.2.2

SQLite V3.38

Oracle Express Edition V21c

SQL Server V2019

具体使用请参考app.yml配置文件以及entry-*.xml和db目录下的若干xml配置文件。


ChangeSet配置详解

变更集:changeSet

  • 属性id: 必须全局唯一

  • 属性author: 该changeSet的作者

  • 属性failOnError: [可选项]运行出错时是否终止运行,默认为true

  • 属性runAlways: [可选项]该changeSet是否每次都运行,默认为false

  • 属性dbms: [可选项]该changeSet适用的数据库类型,默认为all,例如:mysql,dm,!sqlite 表示适用mysql和达梦,不适用sqlite

  • 属性ignore: [可选项]是否忽略该changeSet,默认为false,不忽略

  • 元素comment: [可选项]该changeSet的注释说明,会记入db_change_set管理表的changeset_comment字段中

<changeSet id="app01-ddl-03-test-dbms" author="liquigo" failOnError="false" runAlways="true" dbms="mysql,!sqlite,!h2">
    <comment>comment of this changeSet</comment>
    ...
</changeSet>
<changeSet id="app01-dml-03-test-ignore" author="liquigo" ignore="true">
    <comment>ignore propertie for testing changeSet</comment>
    ...
</changeSet>

创建表:createTable

<createTable tableName="test_column_type" remarks="test the data type of the field">
    <column name="type_boolean" type="boolean" />
    <column name="type_bit6" type="bit(6)" />
    <column name="type_tinyint" type="tinyint" />
    <column name="type_smallint" type="smallint" />
    <column name="type_mediumint" type="mediumint" />
    <column name="type_int" type="int" />
    <column name="type_integer" type="integer" />
    <column name="type_bigint" type="bigint" />
    <column name="type_float" type="float(6,2)" />
    <column name="type_real" type="real(5,2)" />
    <column name="type_double" type="double(10,3)" />
    <column name="type_decimal" type="decimal(15,3)" />
    <column name="type_numeric" type="numeric(10,0)" />
    <column name="type_number" type="number(10,0)" />
    <column name="type_char" type="char(36)" />
    <column name="type_varchar" type="varchar(36)" />
    <column name="type_binary" type="binary(36)" />
    <column name="type_varbinary" type="varbinary(36)" />
    <column name="type_tinyblob" type="tinyblob" />
    <column name="type_blob" type="blob" />
    <column name="type_mediumblob" type="mediumblob" />
    <column name="type_longblob" type="longblob" />
    <column name="type_tinytext" type="tinytext" />
    <column name="type_text" type="text" />
    <column name="type_mediumtext" type="mediumtext" />
    <column name="type_longtext" type="longtext" />
    <column name="type_datetime" type="datetime" />
    <column name="type_timestamp" type="timestamp" />
    <column name="type_date" type="date" />
    <column name="type_time" type="time" />
    <column name="type_uuid" type="uuid" />
    <column name="type_currency" type="currency" />
</createTable>
<createTable tableName="test_role" remarks="test role">
    <column name="id" type="varchar(36)">
        <constraints primaryKey="true" nullable="false" primaryKeyName="pk_test_role_key" />
    </column>
    <column name="creator" type="varchar(36)" defaultValue="${createUser.defaultValue}" />
    <column name="created" type="decimal(15)" defaultValue="1" />
    <column name="updater" type="varchar(36)" defaultValue="${createUser.defaultValue}" />
    <column name="updated" type="decimal(15)" defaultValue="1" />
    <column name="uuid" type="varchar(36)">
        <constraints primaryKey="true" nullable="false" primaryKeyName="pk_test_role_key"
                    unique="true" uniqueConstraintName="uk_test_role_uuid"/>
    </column>
    <column name="role_name" type="varchar(50)" remarks="role name">
        <constraints unique="true" nullable="false" uniqueConstraintName="uk_test_role_name" />
    </column>
    <column name="detail" type="varchar(250)" defaultValue="role" remarks="role detail" >
        <constraints nullable="false" />
    </column>
    <column name="app_id" type="varchar(36)" defaultValue="3101" remarks="foreign key sum_app.id" />
</createTable>

对应生成的适配达梦的sql脚本如下:

create table test_column_type (
  type_boolean bit,
  type_bit6 bit,
  type_tinyint tinyint,
  type_smallint smallint,
  type_mediumint int,
  type_int int,
  type_integer integer,
  type_bigint bigint,
  type_float float,
  type_real real,
  type_double double,
  type_decimal decimal(15,3),
  type_numeric numeric(10,0),
  type_number number(10,0),
  type_char char(36),
  type_varchar varchar(36),
  type_binary binary(36),
  type_varbinary varbinary(36),
  type_tinyblob blob,
  type_blob blob,
  type_mediumblob blob,
  type_longblob blob,
  type_tinytext text,
  type_text text,
  type_mediumtext text,
  type_longtext text,
  type_datetime datetime,
  type_timestamp timestamp,
  type_date date,
  type_time time,
  type_uuid varchar(36),
  type_currency decimal(15,2)
);
comment on table test_column_type is 'test the data type of the field';

create table test_role (
  id varchar(36) not null,
  creator varchar(36) default '20000',
  created decimal(15) default 1,
  updater varchar(36) default '20000',
  updated decimal(15) default 1,
  uuid varchar(36) not null,
  role_name varchar(50) not null,
  detail varchar(250) not null default 'role',
  app_id varchar(36) default '3101',
  constraint pk_test_role_key primary key (id,uuid)
);
comment on table test_role is 'test role';
create unique index uk_test_role_uuid on test_role (uuid);
create unique index uk_test_role_name on test_role (role_name);
comment on column test_role.role_name is 'role name';
comment on column test_role.detail is 'role detail';
comment on column test_role.app_id is 'foreign key sum_app.id';

删除表:dropTable

<dropTable cascadeConstraints="true" tableName="test_t03"/>

对应生成的适配达梦的sql脚本如下:

drop table test_t03 cascade constraints;

重命名表:renameTable

<renameTable oldTableName="test_rename_table" newTableName="test_rename_table_new" />

对应生成的适配达梦的sql脚本如下:

alter table test_rename_table rename to test_rename_table_new;

添加列:addColumn

<addColumn tableName="test_t04">
    <column name="first_login_time" type="varchar(30)" remarks="first login time, yyyy-MM-dd HH:mm:ss" />
    <column name="login_count" type="decimal(7)" defaultValue="0" remarks="login success count">
        <constraints nullable="false"/>
    </column>
    <column name="login_account" type="varchar(20)" defaultValue="default value" remarks="login account">
        <constraints unique="true" nullable="false" uniqueConstraintName="uk_user_login_account" />
    </column>
</addColumn>

对应生成的适配达梦的sql脚本如下:

alter table test_t04 add first_login_time varchar(30);
comment on column test_t04.first_login_time is 'first login time, yyyy-MM-dd HH:mm:ss';
alter table test_t04 add login_count decimal(7) not null default 0;
comment on column test_t04.login_count is 'login success count';
alter table test_t04 add login_account varchar(20) not null default 'default value';
comment on column test_t04.login_account is 'login account';
create unique index uk_user_login_account on test_t04 (login_account);

删除列:dropColumn

<dropColumn columnName="first_login_time" tableName="test_t04"/>
<dropColumn tableName="test_t04">
    <column name="login_count"/>
    <column name="login_account"/>
</dropColumn>

对应生成的适配达梦的sql脚本如下:

alter table test_t04 drop column first_login_time cascade;
alter table test_t04 drop column login_count cascade;
alter table test_t04 drop column login_account cascade;

重命名列:renameColumn

<renameColumn columnDataType="varchar(36)"
        newColumnName="new_app_id"
        oldColumnName="app_id"
        remarks="app id"
        tableName="test_t04"/>

对应生成的适配达梦的sql脚本如下:

alter table test_t04 rename column app_id to new_app_id;
comment on column test_t04.new_app_id is 'app id';

变更列:modifyDataType

<modifyDataType columnName="new_app_id" newDataType="varchar(50)" tableName="test_t04"/>
<modifyDataType columnName="org_id" newDataType="varchar(70)" tableName="test_t04"/>

对应生成的适配达梦的sql脚本如下:

alter table test_t04 modify new_app_id varchar(50);
alter table test_t04 modify org_id varchar(70);

删除默认值:dropDefaultValue

<dropDefaultValue columnDataType="varchar(250)" columnName="detail" tableName="test_role"/>

对应生成的适配达梦的sql脚本如下:

alter table test_role modify detail default null;

创建视图:createView

<createView fullDefinition="false"
        replaceIfExists="true"
        remarks="view of test role"
        viewName="v_test_role">
    select id, role_name, app_id from test_role where created >= 1644800296000;
</createView>

对应生成的适配达梦的sql脚本如下:

drop view if exists v_test_role;
create or replace view v_test_role as 
select id, role_name, app_id from test_role where created >= 1644800296000;
comment on view v_test_role is 'view of test role';

删除视图:dropView

<dropView viewName="v_test_role" dropIfExists="true"/>

对应生成的适配达梦的sql脚本如下:

drop view if exists v_test_role;

创建索引:createIndex

<createIndex indexName="idx_test_property_person_name" tableName="${tableName}">
    <column name="person_name" type="varchar(100)" />
</createIndex>
<createIndex indexName="idx_test_property_id_card" tableName="${tableName}" unique="true">
    <column name="id_card" type="varchar(150)" />
</createIndex>

对应生成的适配达梦的sql脚本如下:

create index idx_test_property_person_name on test_property_replace (person_name);
create unique index idx_test_property_id_card on test_property_replace (id_card);

删除索引:dropIndex

<dropIndex indexName="uk_test_role_name" tableName="test_role"/>

对应生成的适配达梦的sql脚本如下:

drop index uk_test_role_name;

属性替换${}

<!-- entry-***.xml -->
<property name="tableName" value="test_property_replace" dbms="all" />
<property name="pk" value="pk_"/>
<property name="a" value="aaa"/>
<property name="b" value="bbb"/>
<property name="c" value="ccc"/>
<property name="d" value="default ddd"/>
<property name="date" value="date" dbms="oracle" />
<property name="date" value="datetime" dbms="mysql,mariadb,mssql,tidb" />
<property name="date" value="timestamp" dbms="hsqldb" />
<property name="date" value="timestamp" dbms="h2" />
<property name="date" value="date" dbms="dm" />
<property name="date" value="date" dbms="kingbase" />
<property name="date" value="integer" dbms="sqlite" />
<property name="date" value="timestamp" dbms="postgres" />
<property name="createUser.defaultValue" value="20000" dbms="none" />

<!-- changeSet -->
<createTable tableName="${tableName}" remarks="test property replace">
    <column name="id" type="varchar(36)">
        <constraints primaryKey="true" nullable="false"
                        primaryKeyName="${pk}test_property_replace" />
    </column>
    <column name="creator" type="varchar(36)" defaultValue="${createUser.defaultValue}" />
    <column name="create_time" type="decimal(15)" defaultValue="1" />
    <column name="person_name" type="varchar(100)" remarks="person name"/>
    <column name="gender" type="varchar(20)" remarks="gender" />
    <column name="birthdate" type="${date}" remarks="birth date" />
    <column name="${a}_${b}_${c}" type="varchar(50)" defaultValue="${d}" remarks="multi placer" />
    <column name="person_status" type="varchar(20)" remarks="person status" />
    <column name="telephone" type="varchar(150)" remarks="telephone" />
    <column name="email" type="varchar(50)" remarks="email" />
    <column name="photo" type="text" remarks="photo" />
</createTable>

对应生成的适配达梦的sql脚本如下:

create table test_property_replace (
  id varchar(36) not null,
  creator varchar(36) default '20000',
  create_time decimal(15) default 1,
  person_name varchar(100),
  gender varchar(20),
  birthdate date,
  aaa_bbb_ccc varchar(50) default 'default ddd',
  person_status varchar(20),
  telephone varchar(150),
  email varchar(50),
  photo text,
  constraint pk_test_property_replace primary key (id)
);
comment on table test_property_replace is 'test property replace';
comment on column test_property_replace.person_name is 'person name';
comment on column test_property_replace.gender is 'gender';
comment on column test_property_replace.birthdate is 'birth date';
comment on column test_property_replace.aaa_bbb_ccc is 'multi placer';
comment on column test_property_replace.person_status is 'person status';
comment on column test_property_replace.telephone is 'telephone';
comment on column test_property_replace.email is 'email';
comment on column test_property_replace.photo is 'photo';

执行SQL语句:sql

<sql>
    delete from test_role where created = 1644800296000; -- single line comment
    insert into test_role(id, creator, created, updater, updated, uuid, role_name, detail, app_id) values ('1', '1', 1644800296000, '1', 1644800296000, 'uuid1', 'role_name1', '1', '1');
    <!-- comment1 -->
    insert into test_role(id, creator, created, updater, updated, uuid, role_name, detail, app_id) values ('2', '1', 1644800296000, '1', 1644800296000, 'uuid2', 'role_name2', '1', '1');
    /*
        Multiline comment, append record
    */
    <!--
        comment2
    -->
    insert into test_role(id, creator, created, updater, updated, uuid, role_name, detail, app_id) values ('3', '1', 1644800296000, '1', 1644800296000, 'uuid3', 'role_name3', '1', '1');
    insert into test_role(id, creator, created, updater, updated, uuid, role_name, detail, app_id) values ('4', '4', 1644800296000, '4', 1644800296000, 'uuid4', 'role_name4', '1', '1');
</sql>

执行SQL文件:sqlFile

<sqlFile dbms="!sqlite, !postgres, mysql"
    path="db/app01/app01-01.sql" />
<sqlFile dbms="oracle,dameng"
    path="db/app01/app01-01-oracle.sql" />
<sqlFile dbms="!sqlite, postgres, mysql"
    path="D://dev//vue-front//liquigo//db//app01//app01-02.sql" />

前置条件:preConditions

<changeSet id="app01-ddl-pre-cond-01-logical-true" author="liquigo">
    <comment><![CDATA[ !false = true ]]></comment>
    <preConditions onFail="MARK_RAN" onError="HALT" onFailMessage="Fail Message" onErrorMessage="Error Message">
        <not>
            <tableExists tableName="t_user" />
        </not>
    </preConditions>
    <createTable tableName="test_pre_cond_01">
        <column name="id" type="varchar(36)" />
        <column name="name" type="varchar(36)" />
    </createTable>
</changeSet>

前置条件与或非:not,and,or

<changeSet id="app01-ddl-pre-cond-09-logical-true" author="liquigo">
    <comment><![CDATA[ (true && false) || (true && false) || !(true && false) = true ]]></comment>
    <preConditions onFail="MARK_RAN">
        <or>
            <and>
                <tableExists tableName="test_role_true" />
                <viewExists viewName="v_user_view_false" />
            </and>
            <and>
                <tableExists tableName="test_role_1_true" />
                <viewExists viewName="v_test_role_1_false" />
            </and>
            <not>
                <tableExists tableName="test_role_2_true" />
                <viewExists viewName="v_test_role_2_false" />
            </not>
        </or>
    </preConditions>
    <createTable tableName="test_pre_cond_09">
        <column name="id" type="varchar(36)" />
        <column name="name" type="varchar(36)" />
    </createTable>
</changeSet>

前置条件存在判断:tableExists,viewExists,columnExists,indexExists,sqlCheck

<tableExists tableName="test_role_2_true" />
<viewExists viewName="v_test_role_2_false" />
<columnExists tableName="test_role" columnName="role_name" />
<indexExists indexName="idx_test_property_person_name" />
<sqlCheck expectedResult="1">select count(1) from test_role where id = '1'</sqlCheck>

事务回滚:rollback

<changeSet id="app01-ddl-17-rollback" author="liquigo" runOnChange="true">
    <comment>test preConditions and rollback</comment>
    <preConditions onFail="MARK_RAN">
        <not>
            <tableExists tableName="test_rollback" />
        </not>
    </preConditions>
    <createTable tableName="test_rollback" remarks="test rollback">
        <column name="id" type="varchar(36)">
            <constraints primaryKey="true" nullable="false" primaryKeyName="pk_test_rollback_key" />
        </column>
        <column name="role_name" type="varchar(50)" remarks="role name" />
        <column name="detail" type="varchar(260)" defaultValue="role detail" remarks="role detail" />
        <column name="app_id" type="varchar(36)" remarks="foreign key app.id" />
        <column name="org_id" type="varchar(36)" remarks="foreign key org.id" />
    </createTable>
    <addColumn tableName="test_rollback">
        <column name="first_login_time" type="varchar(30)" remarks="first login time, yyyy-MM-dd HH:mm:ss" />
        <column name="login_count" type="decimal(7)" defaultValue="0" remarks="login count" />
    </addColumn>
    <rollback>
        <dropColumn tableName="test_rollback">
            <column name="login_count"/>
            <column name="first_login_time"/>
        </dropColumn>
        <dropTable cascadeConstraints="true" tableName="test_rollback"/>
    </rollback>
    <rollback>
        drop table test_rollback
    </rollback>
</changeSet>

推荐一个完整的changeSet的结构,按顺序如下:

  1. comment 提供注释说明,用于备忘

  2. preConditions 进行前置条件判断

  3. create/drop/add/.. 一个或多个数据库变更标签

  4. rollback 数据库变更失败后的回滚操作

<changeSet id="app01-ddl-17-rollback" author="liquigo">
    <comment>注释说明,用于备忘</comment>
    <preConditions onFail="MARK_RAN">
        <not>
            <tableExists tableName="test_rollback" />
        </not>
    </preConditions>
    <createTable tableName="test_rollback" remarks="test rollback">
        <column name="id" type="varchar(36)">
            <constraints primaryKey="true" nullable="false" primaryKeyName="pk_test_rollback_key" />
        </column>
        <column name="role_name" type="varchar(50)" remarks="role name" />
        <column name="detail" type="varchar(260)" defaultValue="role detail" remarks="role detail" />
        <column name="app_id" type="varchar(36)" remarks="foreign key app.id" />
        <column name="org_id" type="varchar(36)" remarks="foreign key org.id" />
    </createTable>
    <rollback>
        <dropTable cascadeConstraints="true" tableName="test_rollback"/>
    </rollback>
</changeSet>

开发调试用停止:stop

当运行到包含stop标签的changeSet时停止(包含stop标签的changeSet不运行)。

<changeSet id="..." author="liquigo">
    ...
</changeSet>
<changeSet id="liquigo-stop-for-debug" author="liquigo">
    <stop message="liquigo stop message"/>
</changeSet>
<changeSet id="..." author="liquigo">
    ...
</changeSet>

注意事项

【禁止在sql标签中运行ddl语句】

所有的ddl变更必须使用对应的xml标签配置实现

<changeSet id="app01-create-add-index" author="liquigo">
    <sql splitStatements="true" stripComments="true">
        create unique index idx_sys_dict_type on sys_dict_type(name);
        create index idx_itemcode_sys_dict_item on sys_dict_item(item_code);
    </sql>
</changeSet>
<changeSet id="app01-init-create-06" author="liquigo">
    <sql splitStatements="true" stripComments="true">
        alter table sys_audit_log modify user_agent varchar(250);
    </sql>
</changeSet>
<changeSet id="app01-create-02" author="liquigo">
    <sql splitStatements="true" stripComments="true">
        alter table svc_datax_task add target_name varchar(36);
    </sql>
</changeSet>
BSD 2-Clause License Copyright (c) 2022, 古道西风瘦马 All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

简介

liquigo是一个参考了Liquibase中间件的golang开发的数据库版本管理工具,实现了大多数以xml格式配置的常用语法,并且适配了大多数常用的数据库系统,具体适配有:openGauss,TiDB,OceanBase.MySQL,MariaDB,PostgreSQL,KingbaseES,达梦,Oracle,MsSQLServer,SQLite。 展开 收起
Go 等 2 种语言
BSD-2-Clause
取消

发行版 (2)

全部

贡献者

全部

近期动态

加载更多
不能加载更多了
Go
1
https://gitee.com/west0207/liquigo.git
git@gitee.com:west0207/liquigo.git
west0207
liquigo
liquibase-go
master

搜索帮助