golang-mite の使用方法を示す簡単なサンプル アプリケーション
多くの人がこの質問をするので、移行の使用に関する主な利点を強調するためにこのリストを作成してみました。
バージョン管理: 主要かつ最も重要なことの 1 つは、データベース スキーマのさまざまな変更のバージョン管理ができることです。移行がなければ、これらのスキーマ変更は一貫性がなく追跡不可能となり、バージョン管理の問題やエラーが発生する可能性があります。
ロールバック: 障害が発生した場合に備えて、ロールバック システムが常に必要です。移行システムには常に、データベースに変更を適用するためのメソッドと、変更を迅速かつ一貫して元に戻すためのメソッドが 2 つあります:-)
自動化と CI/CD の統合: 移行を自動化して、CI/CD パイプラインの一部にすることができます。これは、手動介入なしで変更をスムーズかつ一貫してデプロイするのに役立ちます。
他にも多くの利点を見つけることができますが、これらの点が主な利点の適切な要約を表していると思います。
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 アプリケーションを作成して、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() } }
実行すると、同様の出力が得られます。
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
このコマンドは、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
注 : 初めて移行を実行するとき、移行が適用されるバージョン番号を認識するテーブル「schema_migrations」が作成されます。
そして、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 アプリケーションから実行すると、新しいフィールドが表示されます:
次のコマンドを使用すると、適用されたものを簡単にロールバックできます。移住。次の例では、最後に適用された移行を元に戻す方法を確認できます。
#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 が すべての移行 に適用されます!
そして、最後の移行が元に戻され、電話フィールドが削除されたことがわかります :-)
移行にエラーが含まれて実行された場合、その移行は適用できず、移行システムは、この移行が修正されるまでデータベースでのさらなる移行を禁止します。
そして、適用しようとすると、次のようなメッセージが表示されます:
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 サイトの他の関連記事を参照してください。