ホームページ > バックエンド開発 > Golang > Golang で移行を使用する方法

Golang で移行を使用する方法

Linda Hamilton
リリース: 2024-11-09 07:28:02
オリジナル
875 人が閲覧しました

golang-mite の使用方法を示す簡単なサンプル アプリケーション

なぜ移行を使用する必要があるのでしょうか?

多くの人がこの質問をするので、移行の使用に関する主な利点を強調するためにこのリストを作成してみました。

バージョン管理: 主要かつ最も重要なことの 1 つは、データベース スキーマのさまざまな変更のバージョン管理ができることです。移行がなければ、これらのスキーマ変更は一貫性がなく追跡不可能となり、バージョン管理の問題やエラーが発生する可能性があります。

ロールバック: 障害が発生した場合に備えて、ロールバック システムが常に必要です。移行システムには常に、データベースに変更を適用するためのメソッドと、変更を迅速かつ一貫して元に戻すためのメソッドが 2 つあります:-)

自動化と CI/CD の統合: 移行を自動化して、CI/CD パイプラインの一部にすることができます。これは、手動介入なしで変更をスムーズかつ一貫してデプロイするのに役立ちます。

他にも多くの利点を見つけることができますが、これらの点が主な利点の適切な要約を表していると思います。

Golang で移行を実装するにはどうすればよいですか?

Go はそのプロジェクトの移行をネイティブにサポートしていないため、人気のある golang-Migrate パッケージを使用できます。また、GORM などの ORM を使用している場合は、それを使用できます。

どちらのパッケージも非常に人気がありますが、ORM の実装には興味がないので、この例では golang-maigrate を使用します。

コードを見せてください!

簡単なアプリケーションを実装し、それがどのように使用されるかを段階的に見てみましょう。

この記事を進めるには次のものが必要です: Go と Docker Compose を使用した Docker

インフラストラクチャー

ルート ディレクトリにファイル docker-compose.yml を作成します。ここでお気に入りの DB を定義します。私の場合は MariaDB を使用しますが、別の DB を自由に使用してください。

services:
  mariadb:
    image: mariadb:11.5.2
    container_name: mariadb_example_go_migration
    ports:
      - "3306:3306"
    environment:
      - MYSQL_DATABASE=app
      - MYSQL_ROOT_PASSWORD=root
      - TZ=Europe/Berlin
    volumes:
      - mariadbdata:/var/lib/mysql

volumes:
  mariadbdata:
    driver: local

docker compose up -d 
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

必要に応じて、docker-compose の代わりに Docker を直接使用することもできます。

docker volume create -d local mariadbdata
docker run --name mariadb_example_go_migration -p 3306:3306 -e MYSQL_DATABASE=app -e MYSQL_ROOT_PASSWORD=root -e TZ=Europe/Berlin -v mariadbdata:/var/lib/mysql mariadb:11.5.2
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

環境値

データベースに接続するための変数を定義する必要があるルート ディレクトリでファイル .env を作成または更新します。

DATABASE_DSN=root:root@tcp(localhost:3306)/app
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

簡単な golang アプリを作成する

シンプルな golang アプリケーションを作成して、DB 接続を成功させ、データベース内のすべてのテーブルと構造をその構造とともにリストします。 cmd/main.go

package main

import (
 "database/sql"
 "fmt"
 "log"
 "os"
 "text/tabwriter"

 _ "github.com/go-sql-driver/mysql"
 "github.com/joho/godotenv"
)

func main() {
 // Load .env variables
 err := godotenv.Load()
 if err != nil {
  log.Fatal("Error loading .env file")
 }

 // Open connection with MySQL DB
 db, err := sql.Open("mysql", os.Getenv("DATABASE_DSN"))
 if err != nil {
  log.Fatalf("Error opening database: %v\n", err)
 }
 defer db.Close()

 // Ensure that the connection works
 err = db.Ping()
 if err != nil {
  log.Fatalf("Error connecting database: %v\n", err)
 }

 fmt.Println("Connected to database")

 // Execute the SHOW TABLES query to list all tables in the database
 tables, err := db.Query("SHOW TABLES")
 if err != nil {
  log.Fatalf("Failed to execute SHOW TABLES query: %v\n", err)
 }
 defer tables.Close()

 fmt.Println("Database structure:")

 for tables.Next() {
  var tableName string
  if err := tables.Scan(&tableName); err != nil {
   log.Fatalf("Failed to scan table name: %v\n", err)
  }

  w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', tabwriter.Debug)

  fmt.Printf("\n[Table: %s]\n\n", tableName)
  fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", "Field", "Type", "Null", "Key", "Default", "Extra")

  // Get the structure of the current table
  structureQuery := fmt.Sprintf("DESCRIBE %s", tableName)
  columns, err := db.Query(structureQuery)
  if err != nil {
   log.Fatalf("Failed to describe table %s: %v\n", tableName, err)
  }
  defer columns.Close()

  for columns.Next() {
   var field, colType, null, key, defaultVal, extra sql.NullString
   err := columns.Scan(&field, &colType, &null, &key, &defaultVal, &extra)
   if err != nil {
    log.Fatalf("Failed to scan column: %v\n", err)
   }

   fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n",
    field.String, colType.String, null.String, key.String, defaultVal.String, extra.String)
  }

  w.Flush()
 }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

実行すると、同様の出力が得られます。

How to use migrations with Golang

CLIの移行

golang-merge CLI を実行するには、基本的に、CLI をローカルにインストールするか、公式の Docker イメージを介して実行する 2 つの方法があります: 移行/移行。

個人的には Docker バリアントの方が好きですが、このチュートリアルでは両方のバリアントを説明します。

移行を生成する方法

最初のステップは、次のコマンドで空の移行を作成することです。

services:
  mariadb:
    image: mariadb:11.5.2
    container_name: mariadb_example_go_migration
    ports:
      - "3306:3306"
    environment:
      - MYSQL_DATABASE=app
      - MYSQL_ROOT_PASSWORD=root
      - TZ=Europe/Berlin
    volumes:
      - mariadbdata:/var/lib/mysql

volumes:
  mariadbdata:
    driver: local

docker compose up -d 
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
docker volume create -d local mariadbdata
docker run --name mariadb_example_go_migration -p 3306:3306 -e MYSQL_DATABASE=app -e MYSQL_ROOT_PASSWORD=root -e TZ=Europe/Berlin -v mariadbdata:/var/lib/mysql mariadb:11.5.2
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  • ext: 生成されるファイルの拡張子。
  • dir: 移行が作成されるディレクトリ。
  • seq: 移行シーケンス名。

このコマンドは、database/migrations/ フォルダーに 2 つの空のファイル、000001createuserstable.up.sql および 000001createuserstable.down.sql を生成します

000001createuserstable.up.sql ファイルで、テーブル ユーザーを作成するための SQL を定義します。

DATABASE_DSN=root:root@tcp(localhost:3306)/app
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

000001createuserstable.down.sql ファイルで、up によって行われたすべての変更を元に戻す SQL を定義します。この場合、users テーブルを削除する必要があります。

package main

import (
 "database/sql"
 "fmt"
 "log"
 "os"
 "text/tabwriter"

 _ "github.com/go-sql-driver/mysql"
 "github.com/joho/godotenv"
)

func main() {
 // Load .env variables
 err := godotenv.Load()
 if err != nil {
  log.Fatal("Error loading .env file")
 }

 // Open connection with MySQL DB
 db, err := sql.Open("mysql", os.Getenv("DATABASE_DSN"))
 if err != nil {
  log.Fatalf("Error opening database: %v\n", err)
 }
 defer db.Close()

 // Ensure that the connection works
 err = db.Ping()
 if err != nil {
  log.Fatalf("Error connecting database: %v\n", err)
 }

 fmt.Println("Connected to database")

 // Execute the SHOW TABLES query to list all tables in the database
 tables, err := db.Query("SHOW TABLES")
 if err != nil {
  log.Fatalf("Failed to execute SHOW TABLES query: %v\n", err)
 }
 defer tables.Close()

 fmt.Println("Database structure:")

 for tables.Next() {
  var tableName string
  if err := tables.Scan(&tableName); err != nil {
   log.Fatalf("Failed to scan table name: %v\n", err)
  }

  w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', tabwriter.Debug)

  fmt.Printf("\n[Table: %s]\n\n", tableName)
  fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", "Field", "Type", "Null", "Key", "Default", "Extra")

  // Get the structure of the current table
  structureQuery := fmt.Sprintf("DESCRIBE %s", tableName)
  columns, err := db.Query(structureQuery)
  if err != nil {
   log.Fatalf("Failed to describe table %s: %v\n", tableName, err)
  }
  defer columns.Close()

  for columns.Next() {
   var field, colType, null, key, defaultVal, extra sql.NullString
   err := columns.Scan(&field, &colType, &null, &key, &defaultVal, &extra)
   if err != nil {
    log.Fatalf("Failed to scan column: %v\n", err)
   }

   fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n",
    field.String, colType.String, null.String, key.String, defaultVal.String, extra.String)
  }

  w.Flush()
 }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

移行の適用方法

次のコマンドは、保留中のすべての移行を適用します。 up の後に数値を追加することで、適用する移行の数を定義することもできます。

#CLI variant
migrate create -ext sql -dir ./database/migrations -seq create_users_table
ログイン後にコピー
ログイン後にコピー
#Docker CLI variant
docker run --rm -v $(pwd)/database/migrations:/migrations migrate/migrate \
    create -ext sql -dir /migrations -seq create_users_table
ログイン後にコピー
  • path: 移行ディレクトリへのパス。
  • データベース: データベース DSN 接続を定義します。

: 初めて移行を実行するとき、移行が適用されるバージョン番号を認識するテーブル「schema_migrations」が作成されます。

そして、Golang アプリケーションを実行して結果を表示します。

How to use migrations with Golang

新しい移行の追加

users テーブルに新しい列電話を追加します

CREATE TABLE `users` (
    `id` VARCHAR(36) NOT NULL PRIMARY KEY,
    `name` VARCHAR(255) NOT NULL,
    `email` VARCHAR(255) NOT NULL UNIQUE,
    `password` VARCHAR(255) NOT NULL
);
ログイン後にコピー
DROP TABLE IF EXISTS `users`;
ログイン後にコピー
#CLI variant
migrate -path=./database/migrations -database "mysql://root:root@tcp(localhost:3306)/app" up
ログイン後にコピー
#Docker CLI variant
docker run --rm -v $(pwd)/database/migrations:/migrations --network host migrate/migrate \
    -path=/migrations -database "mysql://root:root@tcp(localhost:3306)/app" up
ログイン後にコピー

Golang アプリケーションから実行すると、新しいフィールドが表示されます:

How to use migrations with Golang

移行を元に戻す方法

次のコマンドを使用すると、適用されたものを簡単にロールバックできます。移住。次の例では、最後に適用された移行を元に戻す方法を確認できます。

#CLI variant
migrate create -ext sql -dir ./database/migrations -seq add_column_phone

#Docker CLI variant
docker run --rm -v $(pwd)/database/migrations:/migrations migrate/migrate \
    create -ext sql -dir /migrations -seq add_column_phone
ログイン後にコピー
-- 000002_add_column_phone.up.sql
ALTER TABLE `users` ADD `phone` VARCHAR(255) NULL;
ログイン後にコピー

警告 : 移行の数を定義しない場合、ROLLBACKすべての移行 に適用されます!

そして、最後の移行が元に戻され、電話フィールドが削除されたことがわかります :-)

Display table users without phone field

移行エラーを解決する方法

移行にエラーが含まれて実行された場合、その移行は適用できず、移行システムは、この移行が修正されるまでデータベースでのさらなる移行を禁止します。

そして、適用しようとすると、次のようなメッセージが表示されます:

services:
  mariadb:
    image: mariadb:11.5.2
    container_name: mariadb_example_go_migration
    ports:
      - "3306:3306"
    environment:
      - MYSQL_DATABASE=app
      - MYSQL_ROOT_PASSWORD=root
      - TZ=Europe/Berlin
    volumes:
      - mariadbdata:/var/lib/mysql

volumes:
  mariadbdata:
    driver: local

docker compose up -d 
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

パニックにならないでください。一貫したシステムに戻すのは難しくありません。

まず、破損した移行 (この場合はバージョン 2) を解決する必要があります。

移行が解決したら、システムを強制的に最後の有効なバージョン、この場合はバージョン 1 にする必要があります。

docker volume create -d local mariadbdata
docker run --name mariadb_example_go_migration -p 3306:3306 -e MYSQL_DATABASE=app -e MYSQL_ROOT_PASSWORD=root -e TZ=Europe/Berlin -v mariadbdata:/var/lib/mysql mariadb:11.5.2
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
DATABASE_DSN=root:root@tcp(localhost:3306)/app
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

これで、問題なく移行を再適用できるようになりました ;-)

メイクファイル

生産性を向上させ、これらのコマンドの使用を容易にするために、Makefile を使用できます。以下に、ネイティブ クライアントと Docker の 2 つのバリエーションを示します。

CLI バリアント

package main

import (
 "database/sql"
 "fmt"
 "log"
 "os"
 "text/tabwriter"

 _ "github.com/go-sql-driver/mysql"
 "github.com/joho/godotenv"
)

func main() {
 // Load .env variables
 err := godotenv.Load()
 if err != nil {
  log.Fatal("Error loading .env file")
 }

 // Open connection with MySQL DB
 db, err := sql.Open("mysql", os.Getenv("DATABASE_DSN"))
 if err != nil {
  log.Fatalf("Error opening database: %v\n", err)
 }
 defer db.Close()

 // Ensure that the connection works
 err = db.Ping()
 if err != nil {
  log.Fatalf("Error connecting database: %v\n", err)
 }

 fmt.Println("Connected to database")

 // Execute the SHOW TABLES query to list all tables in the database
 tables, err := db.Query("SHOW TABLES")
 if err != nil {
  log.Fatalf("Failed to execute SHOW TABLES query: %v\n", err)
 }
 defer tables.Close()

 fmt.Println("Database structure:")

 for tables.Next() {
  var tableName string
  if err := tables.Scan(&tableName); err != nil {
   log.Fatalf("Failed to scan table name: %v\n", err)
  }

  w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', tabwriter.Debug)

  fmt.Printf("\n[Table: %s]\n\n", tableName)
  fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", "Field", "Type", "Null", "Key", "Default", "Extra")

  // Get the structure of the current table
  structureQuery := fmt.Sprintf("DESCRIBE %s", tableName)
  columns, err := db.Query(structureQuery)
  if err != nil {
   log.Fatalf("Failed to describe table %s: %v\n", tableName, err)
  }
  defer columns.Close()

  for columns.Next() {
   var field, colType, null, key, defaultVal, extra sql.NullString
   err := columns.Scan(&field, &colType, &null, &key, &defaultVal, &extra)
   if err != nil {
    log.Fatalf("Failed to scan column: %v\n", err)
   }

   fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n",
    field.String, colType.String, null.String, key.String, defaultVal.String, extra.String)
  }

  w.Flush()
 }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

Docker CLI のバリアント

#CLI variant
migrate create -ext sql -dir ./database/migrations -seq create_users_table
ログイン後にコピー
ログイン後にコピー

リポジトリ

このチュートリアルのコードは、GitHub - albertcolom/example-go-migration で公開されています


原文の公開場所: albertcolom.com

以上がGolang で移行を使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート