Liquibase:如何使用 CURRENT_TIMESTAMP 加载数据?

Posted

技术标签:

【中文标题】Liquibase:如何使用 CURRENT_TIMESTAMP 加载数据?【英文标题】:Liquibase: how to load data with CURRENT_TIMESTAMP? 【发布时间】:2020-06-26 14:54:58 【问题描述】:

我正在尝试更新我的项目,从

    <liquibase.version>3.5.5</liquibase.version>
    <liquibase-hibernate5.version>3.6</liquibase-hibernate5.version>

    <liquibase.version>3.9.0</liquibase.version>
    <liquibase-hibernate5.version>3.8</liquibase-hibernate5.version>

我在从 CSV 文件加载数据时遇到了一些问题,这些文件包含一些以当前时间戳为值的列。

例如我的 CSV 文件:

id;name;created;modified
1;Book A;now();now()
2;Book B;now();now()

Book 表是通过以下方式创建的:

<createTable tableName="book">
    <column name="id" type="bigint" autoIncrement="$autoIncrement">
        <constraints primaryKey="true" nullable="false"/>
    </column>
    <column name="name" type="varchar(255)">
        <constraints nullable="false"/>
    </column>
    <column name="created" type="timestamp">
        <constraints nullable="false"/>
    </column>
    <column name="modified" type="timestamp">
        <constraints nullable="false"/>
    </column>
</createTable>

并且数据被加载:

<property name="now" value="current_timestamp" dbms="postgresql"/>

<changeSet id="20180508144233-1" author="developer">
    <loadData catalogName="public"
              encoding="UTF-8"
              file="config/liquibase/books.csv"
              schemaName="public"
              separator=";"
              quotchar="'"
              tableName="book">
    </loadData>
</changeSet>

使用以前版本的 Liquibase 可以正常工作,但是更新后我收到以下错误:

2020-06-26 16:49:57 [project-Executor-1] [ERROR] liquibase.changelog.ChangeSet - Change Set config/liquibase/changelog/20180508144233_added_books_data.xml::20180508144233-1::developer failed.  Error: liquibase.exception.DateParseException: Improper value in 'NOW' value: now(). 'NOW' must be followed by + or -, then numeric offset, then units (hours, minutes, days, or years
Hibernate: select answerweig0_.id as id1_1_, answerweig0_.likelihood as likeliho2_1_, answerweig0_.question_type as question3_1_, answerweig0_.weight as weight4_1_ from answer_weight answerweig0_
2020-06-26 16:49:57 [project-Executor-1] [ERROR] i.g.j.c.l.AsyncSpringLiquibase - Liquibase could not start correctly, your database is NOT ready: Migration failed for change set config/liquibase/changelog/20180508144233_added_books_data.xml::20180508144233-1::developer:
     Reason: liquibase.exception.UnexpectedLiquibaseException: liquibase.exception.DateParseException: Improper value in 'NOW' value: now(). 'NOW' must be followed by + or -, then numeric offset, then units (hours, minutes, days, or years
liquibase.exception.MigrationFailedException: Migration failed for change set config/liquibase/changelog/20180508144233_added_books_data.xml::20180508144233-1::developer:
     Reason: liquibase.exception.UnexpectedLiquibaseException: liquibase.exception.DateParseException: Improper value in 'NOW' value: now(). 'NOW' must be followed by + or -, then numeric offset, then units (hours, minutes, days, or years
    at liquibase.changelog.ChangeSet.execute(ChangeSet.java:646)
    at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:53)
    at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:83)
    at liquibase.Liquibase.update(Liquibase.java:202)
    at liquibase.Liquibase.update(Liquibase.java:179)
    at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:366)
    at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:314)
    at org.springframework.boot.autoconfigure.liquibase.DataSourceClosingSpringLiquibase.afterPropertiesSet(DataSourceClosingSpringLiquibase.java:46)
    at io.github.jhipster.config.liquibase.AsyncSpringLiquibase.initDb(AsyncSpringLiquibase.java:118)
    at io.github.jhipster.config.liquibase.AsyncSpringLiquibase.lambda$afterPropertiesSet$0(AsyncSpringLiquibase.java:93)
    at io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor.lambda$createWrappedRunnable$1(ExceptionHandlingAsyncTaskExecutor.java:78)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

【问题讨论】:

【参考方案1】:

作为一种解决方法,我可以通过在表创建更改日志中使用默认值来设置此类列的值:

<createTable tableName="book">
    <column name="id" type="bigint" autoIncrement="$autoIncrement">
        <constraints primaryKey="true" nullable="false"/>
    </column>
    <column name="name" type="varchar(255)">
        <constraints nullable="false"/>
    </column>
    <column name="created" type="timestamp" defaultValueComputed="CURRENT_TIMESTAMP">
        <constraints nullable="false"/>
    </column>
    <column name="modified" type="timestamp" defaultValueComputed="CURRENT_TIMESTAMP">
        <constraints nullable="false"/>
    </column>
</createTable>

并从 CSV 文件中删除相应的列:

id;name
1;Book A
2;Book B

但是,我仍在寻找将 CURRENT_TIMESTAMP 值保留在 CSV 文件中的方法。

【讨论】:

这应该是公认的答案!这正是我需要的:)【参考方案2】:

您的解决方法非常正确。但是根据数据库,您必须添加一种方式,使您的 update_timestamp 或修改的时间戳将根据您在此数据库行中的每次添加、减少或编辑而更改。例如,这是在 PostgresSQL 中设置的方法。

<changeSet id="UNIQUE_ID" author="YOUR_NAME">
    <preConditions onFail="MARK_RAN">
        <dbms type="postgresql"/>
    </preConditions>
    <createProcedure>
        CREATE OR REPLACE FUNCTION refresh_updated_date_column()
        RETURNS TRIGGER AS $$
        BEGIN
        NEW.updated_date = now();
        RETURN NEW;
        END;
        $$ language 'plpgsql';
    </createProcedure>
    <rollback>
        DROP FUNCTION IF EXISTS refresh_updated_date_column;
    </rollback>
</changeSet>`

这将是您在创建表和添加所需列的原始变更集之后添加的附加变更集。

【讨论】:

以上是关于Liquibase:如何使用 CURRENT_TIMESTAMP 加载数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 liquibase 更改架构名称

Liquibase 和 Spring 如何使用单独的用户进行架构更改

如何使用 jar 文件中的 Liquibase 更改日志

Liquibase 如何标记 - 命令行

如何在春季测试中使用 liquibase 解决“已经有太多客户”的问题?

如何修复未清除的 Liquibase 数据库锁