Liquibase & MySQL 5.7 时间戳列修改问题

Liquibase & MySQL 5.7 timestamp column modification problem

我有一个名为 updated_time 的列,它分配了 timestamp 数据类型:

`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP 

问题是目前这个列支持秒精度。我需要它能够存储毫秒精度。

因此,我准备了以下 Liquibase 变更集:

{
  "databaseChangeLog": [
    {
      "changeSet": {
        "id": "1",
        "changes": [
          {
            "modifyDataType": {
              "columnName": "updated_time",
              "newDataType": "timestamp(3)",
              "tableName": "mytable"
            },
            "addDefaultValue": {
              "columnDataType": "timestamp(3)",
              "columnName": "updated_time",
              "defaultValueComputed": "current_timestamp(3)",
              "tableName": "mytable"
            },
            "addNotNullConstraint": {
              "columnDataType": "timestamp(3)",
              "columnName": "updated_time",
              "tableName": "mytable"
            }
          }
        ]
      }
    }
  ]
}

不幸的是,这个变更集总是失败。

原因如下:

2019-11-08 00:57:28.624  WARN [] 99326 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is liquibase.exception.MigrationFailedException: Migration failed for change set ...
     Reason: liquibase.exception.DatabaseException: Invalid default value for 'updated_time' [Failed SQL: (1067) ALTER TABLE maas.mytable MODIFY updated_time timestamp(3)]

我看到一些帖子说 5.7 版中 timestamp 数据类型发生了一些变化。也就是说,默认情况下,我无法为 timestamp 列分配非零(空)值。而且,为了修复它,我必须对服务器配置本身进行一些更改。 假设我对服务器的访问权限有限,我不能简单地去修改配置,在 Liquibase 中是否有解决此问题的优雅方法?

如果你想将timestamp转换成bigint,那么你可以通过以下方式进行:

  • 创建一个新列,例如bigint_date;
  • 使用当前 timestamp_date 列中的 bigint 值填充它;
  • 删除您的 timestamp_date 列;

Liquibase 变更集可能如下所示:

<changeSet id="foo1" author="bar">
    <preConditions onFail="MARK_RAN">
        <not>
            <columnExists tableName="your_table" columnName="bigint_date"/>
        </not>
    </preConditions>
    <comment>Add new column</comment>
    <addColumn tableName="your_table">
        <column name="bigint_date" type="bigint(13)"/>
    </addColumn>
</changeSet>
<changeSet id="foo2" author="bar">
    <preConditions onFail="MARK_RAN">
        <columnExists tableName="your_table" columnName="bigint_date"/>
        <columnExists tableName="your_table" columnName="timestamp_date"/>
    </preConditions>
    <comment>Populate it with bigint values from your current "timestamp_date" column</comment>
    <update tableName="your_table">
        <column name="bigint_date" valueComputed="SELECT UNIX_TIMESTAMP(timestamp_date) FROM your_table"/>
    </update>
</changeSet>
<changeSet id="foo3" author="bar">
    <preConditions onFail="MARK_RAN">
        <columnExists tableName="your_table" columnName="timestamp_date"/>
    </preConditions>
    <comment>Drop your "timestamp_date" column</comment>
    <dropColumn tableName="your_table" columnName="timestamp_date"/>
</changeSet>
<changeSet id="foo4" author="bar">
    <preConditions onFail="MARK_RAN">
        <columnExists tableName="your_table" columnName="bigint_date"/>
    </preConditions>
    <comment>Update NULL values</comment>
    <update tableName="your_table">
        <column name="bigint_date" valueComputed="UNIX_TIMESTAMP()"/>
        <where>bigint_date IS NULL</where>
    </update>
</changeSet>