我在Docker内部的Golang上编写的两个应用程序之间迁移PostgreSQL时遇到了问题. 只创建了一个表,该表首先通过Docker容器migrations.

我使用迁移工具.第一个应用程序是"项目",第二个应用程序是"订单".在这些应用程序的每个目录中都有"迁移"文件夹.在"Projects/migrations"中分别有001_tag_items_up.sql和"down",在"order/migrations"中有001_create_order_up. sql.If start the "items" container first, the table for "order" will not be created and vice versa.

001_CREATE_ITEMS_up.sql

CREATE TABLE IF NOT EXISTS items (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    price DECIMAL NOT NULL
);

001_create_order_up.sql

CREATE TABLE IF NOT EXISTS orders (
    id SERIAL PRIMARY KEY,
    item_id INT NOT NULL,
    quantity INT DEFAULT 1
);

两个应用的Dockerfile

FROM golang:1.22 as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o service .
FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/service .
COPY --from=builder /app/migrations /root/migrations
CMD ["./service"]

docker—compose

version: '3.8'
services:
  postgres:
    image: postgres:13
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: dbname
    ports:
      - "5432:5432"
    volumes:
      - /database:/var/lib/postgresql_data
  items-service:
    build: 
      context: /items
      dockerfile: Dockerfile
    depends_on:
      - postgres
  orders-service:
    build: 
      context: /order
      dockerfile: Dockerfile
    depends_on:
      - postgres

应用程序的代码"项目"和"订单"

package main

import (
    "log"

    "github.com/golang-migrate/migrate/v4"
    _ "github.com/golang-migrate/migrate/v4/database/postgres"
    _ "github.com/golang-migrate/migrate/v4/source/file"
)

func main() {
    m, err := migrate.New(
        "file://migrations",
        "postgres://user:password@postgres:5432/dbname?sslmode=disable",
    )
    if err != nil {
        log.Fatalf("migration failed to initialize: %v", err)
    }
    if err := m.Up(); err != nil && err != migrate.ErrNoChange {
        log.Fatalf("migration failed: %v", err)
    }
}

推荐答案

您使用的工具Go-Migrate假定每个数据库只有一个目录.它将数字标识符(递增数字或日期时间)存储在一个表中,以确定数据库的版本,因此它知道要做什么.

如果您使用递增的数字(如您在问题中所做的),当您的第二个服务启动时,migrate将认为所有的迁移都已经执行.

如果您使用DateTime(就像您基于@DavidMaze的 comments 所try 的那样),您会发现Migrate可能会看到数据库将其设置为比最高的up更高的版本,因此,try 降级,结果发现没有down脚本.

解决这个问题的方法是使用x-migrationlayui-table选项来指示迁移使用different表来跟踪两个不同应用程序的migrations.

所以你的main分会变成这样:


func main() {
    m, err := migrate.New(
        "file://migrations",
        "postgres://user:password@postgres:5432/dbname?sslmode=disable&x-migrationlayui-table=orders-service-schema",
    )

    // your error handling and what not
}

Postgresql相关问答推荐

org.postgresql. util.PSQLException:使用docker + docker—compose + kafka + springboot时try 连接失败

我需要一个变量来引用上周的星期五

如何在PostgreSQL中以行值的形式获取列

尽管违反了部分索引约束,Postgres 插入仍在发生

空表上的 Postgres 意外行为

使用 GDB 调试器调试 AGE 代码的过程

PostgreSQL - 列出模式中的所有唯一约束

Postgres 14 反斜杠 Z 没有给出正确的输出

Windows上的psql:错误:编码UTF8的字节序列无效:0xc8 0x20

使用 postgresql Select 整数作为位和状态表

如何在 postgresql 上使用 sqlalchemy 进行正确的 upsert?

postgresql查询中的正则表达式不区分大小写

在postgres的同一列中存储不同数据类型的合理方法?

在这个 Dockerfile 中创建的 Postgres 用户名/密码在哪里?

Postgres 日期重叠约束

Postgres - 如果找不到记录,则在更新时返回错误

如何增加 max_locks_per_transaction

在 PostgreSQL 中将列数据类型从 Text 更改为 Integer

如何使用 Django Migrations 重新创建已删除的表?

Capistrano 与 PostgreSQL,错误:database is being accessed by other users