首页 > 解决方案 > Liquibase:如何从 CSV 加载日期字段?

问题描述

我在一个 Spring-Boot 项目中,我正在使用 Liquibase 来从 CSV 文件填充数据库。其中,有一些实体带有日期字段。

这是我用于创建表的 databaseChangelog:

<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
    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.5.xsd
                        http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <property name="now" value="now()" dbms="h2"/>

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

    <property name="floatType" value="float4" dbms="postgresql, h2"/>
    <property name="floatType" value="float" dbms="mysql, oracle, mssql"/>

    <!--
        Added the entity Container.
    -->
    <changeSet id="20180424154826-1" author="jhipster">
        <createTable tableName="container">
            <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="description" type="varchar(2000)">
                <constraints nullable="true" />
            </column>

            <column name="container_type" type="varchar(255)">
                <constraints nullable="true" />
            </column>

            <column name="created" type="timestamp">
                <constraints nullable="true" />
            </column>

            <!-- jhipster-needle-liquibase-add-column - JHipster will add columns here, do not remove-->
        </createTable>
        <dropDefaultValue tableName="container" columnName="created" columnDataType="datetime"/>

    </changeSet>
    <!-- jhipster-needle-liquibase-add-changeset - JHipster will add changesets here, do not remove-->
</databaseChangeLog>

这里是用于填充表的更改日志:

<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
    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.5.xsd
                        http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <property name="now" value="now()" dbms="h2"/>

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

    <property name="floatType" value="float4" dbms="postgresql, h2"/>
    <property name="floatType" value="float" dbms="mysql, oracle, mssql"/>

    <!--
        Added the entity ExternalAudit.
    -->
    <changeSet id="20180425154950-1" author="developer">
        <loadData catalogName="container"
                  encoding="UTF-8"
                  file="config/liquibase/containers.csv"
                  schemaName="public"
                  separator=";"
                  quotchar="'"
                  tableName="container">
        </loadData>
    </changeSet>
    <!-- jhipster-needle-liquibase-add-changeset - JHipster will add changesets here, do not remove-->
</databaseChangeLog>

最后是包含表格数据的 CSV:

id;name;description;container_type;created
1;'Human';'Human container';'HUMAN';${now}
2;'IT';'IT container';'IT';${now}
3;'Physical';'Physical container';'PHYSICAL';${now}
4;'Intangible';'Intangible container';'INTANGIBLE';${now}

问题是,如果我运行:

mvn clean install

我在控制台中收到以下日志,抱怨日期字段:

nested exception is liquibase.exception.MigrationFailedException: Migration failed for change set config/liquibase/changelog/20180425154950_added_Containers_data.xml::20180425154950-1::developer:
     Reason: liquibase.exception.DatabaseException: Cannot parse "TIMESTAMP" constant "${now}"; SQL statement:
INSERT INTO public.container (id, name, description, container_type, created) VALUES ('1', 'Human', 'Human container', 'HUMAN', '${now}') -- ('1', 'Human', 'Human container', 'HUMAN', '${now}') [22007-197] [Failed SQL: INSERT INTO public.container (id, name, description, container_type, created) VALUES ('1', 'Human', 'Human container', 'HUMAN', '${now}')]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1630)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1080)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:857)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Caused by: liquibase.exception.MigrationFailedException: Migration failed for change set config/liquibase/changelog/20180425154950_added_Containers_data.xml::20180425154950-1::developer:
     Reason: liquibase.exception.DatabaseException: Cannot parse "TIMESTAMP" constant "${now}"; SQL statement:
INSERT INTO public.container (id, name, description, container_type, created) VALUES ('1', 'Human', 'Human container', 'HUMAN', '${now}') -- ('1', 'Human', 'Human container', 'HUMAN', '${now}') [22007-197] [Failed SQL: INSERT INTO public.container (id, name, description, container_type, created) VALUES ('1', 'Human', 'Human container', 'HUMAN', '${now}')]
    at liquibase.changelog.ChangeSet.execute(ChangeSet.java:619)
    at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:51)
    at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:79)
    at liquibase.Liquibase.update(Liquibase.java:214)
    at liquibase.Liquibase.update(Liquibase.java:192)
    at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:431)
    at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:388)
    at io.github.jhipster.config.liquibase.AsyncSpringLiquibase.initDb(AsyncSpringLiquibase.java:94)
    at io.github.jhipster.config.liquibase.AsyncSpringLiquibase.afterPropertiesSet(AsyncSpringLiquibase.java:84)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1688)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1626)
    ... 43 common frames omitted

如果我运行:

mvn process-resources
mvn liquibase:update

结果是建立成功

标签: timestampliquibase

解决方案


在您的 csv 中,只需使用now而不是${now}. 然后它不应该再扔Cannot parse "TIMESTAMP" constant "${now}";


推荐阅读