使用golang-migrate时出现脏数据库版本错误

23

我是 golang-migrate 的新用户。

我已经成功地运行了一些迁移。

我目前在开发模式下,所以我想重新运行这些迁移,因此在连接到我的数据库后,我在 psql shell 中执行了 drop database schema_migrations

现在的问题是当我运行执行迁移的代码(如下所示)时:


func RunMigrations() {
    m, err := migrate.New(
        "file://db/migrations",
        "postgres://postgres:postgres@localhost:5432/mydatabase?sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    if err := m.Up(); err != nil {
        if err.Error() == "no change" {
            log.Println("no change made by migration scripts")
        } else {
            log.Fatal(err)
        }
    }
}

我遇到了这个错误

数据库版本2存在问题。请修复并强制更新版本。

这个错误是什么意思,我该如何解决?

5个回答

24

Dirty database version 2 意味着您尝试运行第二个版本的迁移,但失败了。

如果迁移失败,数据库可能不一致或损坏。

在损坏的状态上运行其他迁移是不可预测的,因此在清理数据库之前,迁移会被阻止。

https://github.com/golang-migrate/migrate/blob/master/FAQ.md#what-does-dirty-database-mean

"Dirty" 数据库是什么意思?

在迁移运行之前,每个数据库都会设置一个 dirty 标志。如果迁移失败并且脏状态持久存在,则执行会停止,这会防止尝试在失败的迁移上运行更多迁移。您需要手动修复错误,然后“强制”期望的版本。

在清理数据库后,您还可以打开 schema_migrations 表,并将 Dirty 标志和回滚版本号更改为成功应用的最后一个迁移。


但是为什么删除 schema_migrations 表并不能解决问题呢? - pkaramol
1
迁移应该是安全的。没有 schema_migrations 表的数据库被解释为没有被迁移覆盖的数据库。 - Dmitry Harnitski
1
如果迁移表不存在,go-migrate 将知道它应用的最后一个成功更改。在这种情况下,go-migrate 将从头开始尝试升级到最新版本。 - not-a-robot
2
如果多个服务使用同一个数据库,一个好的实践是指定一个迁移表,该表应该由go-migrate使用。依赖于同一张表,您将无法从不同的位置升级单独服务的表。 - not-a-robot
1
请注意,如果您想跳过存在问题的迁移,请将 schema_migrations 条目的 dirty 标志设置为 false 并重新部署您的服务。 - Ashutosh Chamoli

2
当发生这种情况时,您可能需要手动修复错误。
然后,使用CLI工具可以清理数据库。基本上,您应该运行: migrate -path PATH_TO_YOUR_MIGRATIONS -database YOUR_DATABASE_URL force VERSION,其中N是DB的当前状态。
您可以在入门文档中了解更多相关信息。

1

进入您的Postgres控制台并在Schema_Migrations表中查找详细信息。

如果您看到Dirty=true,那么您已经找到了根本原因,您只需要运行更新查询来更新它。

请查看以下命令。

select * from schema_migrations;

update schema_migrations set dirty =false where version=XXXX;

0
如果您删除了schema_migrations表,可以通过强制迁移版本来重新创建它。
例如:
m, err := migrate.New("file://db/migrations","postgres://postgres:postgres@localhost:5432/mydatabase?sslmode=disable")
if err != nil {
    log.Fatal(err)
}
err := m.Force(11) //11 is migrations version number, you may use your latest version
if err != nil {
    return err
}

0
我通过将脏标志更新为零来解决了这个错误。 在我的情况下,我的数据库名称是“auth”。因此,我首先运行以下命令来检查脏版本。
select * from auth_migrations

在输出中,我发现列“dirty”具有值1。

然后我将其更新为零,我的问题得到解决。

注意:如果您的数据库名称为“exampleDb”,则您的脏版本将位于“exampleDb_migrations”中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接