ホームページ >データベース >mysql チュートリアル >Golang サービスの DB 移行、なぜそれが重要なのか?
更新されたデータベース スキーマを使用して新しい更新を実稼働環境にデプロイしたが、その後バグが発生し、元に戻す必要があるという状況に直面したことはありませんか。移行が必要になるのはそのときです。
データベースの移行は、いくつかの重要な目的を果たします。
MySQL で GORM を使用し、簡単な移行、更新、ロールバックを可能にする、Golang サービスの包括的な運用グレードのセットアップを作成するには、移行ツールを組み込み、データベース接続プーリングを処理し、適切な構造体定義を確保する必要があります。プロセスをガイドする完全な例を次に示します:
/golang-service |-- main.go |-- database | |-- migration.go |-- models | |-- user.go |-- config | |-- config.go |-- migrations | |-- ... |-- go.mod
package config import ( "fmt" "log" "os" "time" "github.com/joho/godotenv" "gorm.io/driver/mysql" "gorm.io/gorm" ) var DB *gorm.DB func ConnectDB() { err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // charset=utf8mb4: Sets the character set to utf8mb4, which supports all Unicode characters, including emojis. // parseTime=True: Tells the driver to automatically parse DATE and DATETIME values into Go's time.Time type. // loc=Local: Uses the local timezone of the server for time-related queries and storage. dsn := fmt.Sprintf( "%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_NAME"), ) db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic("failed to connect database") } sqlDB, err := db.DB() if err != nil { panic("failed to configure database connection") } // Set connection pool settings sqlDB.SetMaxIdleConns(10) sqlDB.SetMaxOpenConns(100) sqlDB.SetConnMaxLifetime(time.Hour) // 1.sqlDB.SetMaxIdleConns(10) // Sets the maximum number of idle (unused but open) connections in the connection pool. // A value of 10 means up to 10 connections can remain idle, ready to be reused. // 2. sqlDB.SetMaxOpenConns(100): // Sets the maximum number of open (active or idle) connections that can be created to the database. // A value of 100 limits the total number of connections, helping to prevent overloading the database. // 3. sqlDB.SetConnMaxLifetime(time.Hour): // Sets the maximum amount of time a connection can be reused before it’s closed. // A value of time.Hour means that each connection will be kept for up to 1 hour, after which it will be discarded and a new connection will be created if needed. DB = db }
package database import ( "golang-service/models" "golang-service/migrations" "gorm.io/gorm" ) func Migrate(db *gorm.DB) { db.AutoMigrate(&models.User{}) // Apply additional custom migrations if needed }
package models import "gorm.io/gorm" type User struct { gorm.Model Name string `json:"name"` }
DB_USER=root DB_PASS=yourpassword DB_HOST=127.0.0.1 DB_PORT=3306 DB_NAME=yourdb
package main import ( "golang-service/config" "golang-service/database" "golang-service/models" "github.com/gin-gonic/gin" "gorm.io/gorm" ) func main() { config.ConnectDB() database.Migrate(config.DB) r := gin.Default() r.POST("/users", createUser) r.GET("/users/:id", getUser) r.Run(":8080") } func createUser(c *gin.Context) { var user models.User if err := c.ShouldBindJSON(&user); err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } if err := config.DB.Create(&user).Error; err != nil { c.JSON(500, gin.H{"error": err.Error()}) return } c.JSON(201, user) } func getUser(c *gin.Context) { id := c.Param("id") var user models.User if err := config.DB.First(&user, id).Error; err != nil { c.JSON(404, gin.H{"error": "User not found"}) return } c.JSON(200, user) }
実稼働環境の場合、golang-Migrate のような移行ライブラリを使用して、移行を適用、ロールバック、またはやり直すことができます。
golang-移行をインストールします:
go install -tags 'mysql' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
ユーザーテーブルの移行ファイルを生成
migrate create -ext=sql -dir=./migrations -seq create_users_table
コマンドを実行すると、.up.sql (スキーマを更新するため) と down.sql (後でロールバックする可能性があるため) のペアが取得されます。番号 000001 は、自動生成された移行のインデックスです。
/golang-service |-- migrations | |-- 000001_create_users_table.down.sql | |-- 000001_create_users_table.up.sql
関連する sql コマンド を .up ファイルと .down ファイルに追加します。
000001_create_users_table.up.sql
CREATE TABLE users ( id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, created_at DATETIME, updated_at DATETIME, deleted_at DATETIME);
000001_create_users_table.down.sql
DROP TABLE IF EXISTS users;
次のコマンド (ログの詳細を表示するには -verbose フラグ) を使用して、アップ移行を実行し、データベースに変更を適用します。
migrate -path ./migrations -database "mysql://user:password@tcp(localhost:3306)/dbname" -verbose up
移行で問題が発生した場合は、次のコマンドを使用して現在の移行バージョンとそのステータスを確認できます。
migrate -path ./migrations -database "mysql://user:password@tcp(localhost:3306)/dbname" version
何らかの理由で移行が失敗した場合は、ダーティ マイグレーションのバージョン番号を指定して、force (慎重に使用してください) コマンドを使用することを検討できます。バージョンが 1 の場合 (migrations または schema_migrations テーブルで確認できます)、次を実行します:
migrate -path ./migrations -database "mysql://user:password@tcp(localhost:3306)/dbname" force 1
ある時点で、新しい機能を追加したい場合があり、その中にはデータ スキームの変更が必要になる場合もあります。たとえば、users テーブルに email フィールドを追加したいと考えています。次のようにします。
メール列を users テーブルに追加するための新しい移行を作成します
migrate create -ext=sql -dir=./migrations -seq add_email_to_users
これで、.up.sql と .down.sql の新しいペアができました
/golang-service |-- migrations | |-- 000001_create_users_table.down.sql | |-- 000001_create_users_table.up.sql | |-- 000002_add_email_to_users.down.sql | |-- 000002_add_email_to_users.up.sql
次のコンテンツを *_add_email_to_users.*.sql ファイルに追加します
000002_add_email_to_users.up.sql
/golang-service |-- main.go |-- database | |-- migration.go |-- models | |-- user.go |-- config | |-- config.go |-- migrations | |-- ... |-- go.mod
000002_add_email_to_users.down.sql
package config import ( "fmt" "log" "os" "time" "github.com/joho/godotenv" "gorm.io/driver/mysql" "gorm.io/gorm" ) var DB *gorm.DB func ConnectDB() { err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // charset=utf8mb4: Sets the character set to utf8mb4, which supports all Unicode characters, including emojis. // parseTime=True: Tells the driver to automatically parse DATE and DATETIME values into Go's time.Time type. // loc=Local: Uses the local timezone of the server for time-related queries and storage. dsn := fmt.Sprintf( "%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_NAME"), ) db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic("failed to connect database") } sqlDB, err := db.DB() if err != nil { panic("failed to configure database connection") } // Set connection pool settings sqlDB.SetMaxIdleConns(10) sqlDB.SetMaxOpenConns(100) sqlDB.SetConnMaxLifetime(time.Hour) // 1.sqlDB.SetMaxIdleConns(10) // Sets the maximum number of idle (unused but open) connections in the connection pool. // A value of 10 means up to 10 connections can remain idle, ready to be reused. // 2. sqlDB.SetMaxOpenConns(100): // Sets the maximum number of open (active or idle) connections that can be created to the database. // A value of 100 limits the total number of connections, helping to prevent overloading the database. // 3. sqlDB.SetConnMaxLifetime(time.Hour): // Sets the maximum amount of time a connection can be reused before it’s closed. // A value of time.Hour means that each connection will be kept for up to 1 hour, after which it will be discarded and a new connection will be created if needed. DB = db }
up Migration コマンドを再度実行して、データ スキーマを更新します
package database import ( "golang-service/models" "golang-service/migrations" "gorm.io/gorm" ) func Migrate(db *gorm.DB) { db.AutoMigrate(&models.User{}) // Apply additional custom migrations if needed }
新しいスキーマとの同期を保つために、golang ユーザーの構造体を更新する (Email フィールドを追加する) 必要もあります。
package models import "gorm.io/gorm" type User struct { gorm.Model Name string `json:"name"` }
何らかの理由で新しく更新されたスキーマにバグが発生し、ロールバックする必要がある場合は、down コマンドを使用します。
DB_USER=root DB_PASS=yourpassword DB_HOST=127.0.0.1 DB_PORT=3306 DB_NAME=yourdb
番号 1 は、1 つの移行をロールバックすることを示します。
ここでは、データ スキーマの変更を反映するために、golang ユーザーの構造体を手動で更新する (Email フィールドを削除する) 必要もあります。
package main import ( "golang-service/config" "golang-service/database" "golang-service/models" "github.com/gin-gonic/gin" "gorm.io/gorm" ) func main() { config.ConnectDB() database.Migrate(config.DB) r := gin.Default() r.POST("/users", createUser) r.GET("/users/:id", getUser) r.Run(":8080") } func createUser(c *gin.Context) { var user models.User if err := c.ShouldBindJSON(&user); err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } if err := config.DB.Create(&user).Error; err != nil { c.JSON(500, gin.H{"error": err.Error()}) return } c.JSON(201, user) } func getUser(c *gin.Context) { id := c.Param("id") var user models.User if err := config.DB.First(&user, id).Error; err != nil { c.JSON(404, gin.H{"error": "User not found"}) return } c.JSON(200, user) }
移行とロールバックのプロセスを簡素化するために、Makefile を追加できます。
go install -tags 'mysql' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
Makefileの内容は以下の通りです。
migrate create -ext=sql -dir=./migrations -seq create_users_table
これで、CLI で make mitigrate_up または make mitigrate_down を実行するだけで、移行とロールバックを行うことができます。
移行をロールバックしたり、データベースに影響を与える可能性のある変更を加えたりする前に、考慮すべき重要な点がいくつかあります。
データをバックアップすることが重要です。簡単なガイドは次のとおりです:
データベースダンプ:
データベース固有のツールを使用して、データベースの完全バックアップを作成します。 MySQL の場合、以下を使用できます:
/golang-service |-- main.go |-- database | |-- migration.go |-- models | |-- user.go |-- config | |-- config.go |-- migrations | |-- ... |-- go.mod
これにより、dbname データベースのすべてのデータとスキーマを含むファイル (backup_before_rollback.sql) が作成されます。
特定のテーブルをエクスポート:
特定のテーブルのみをバックアップする必要がある場合は、mysqldump コマンドで指定します。
package config import ( "fmt" "log" "os" "time" "github.com/joho/godotenv" "gorm.io/driver/mysql" "gorm.io/gorm" ) var DB *gorm.DB func ConnectDB() { err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // charset=utf8mb4: Sets the character set to utf8mb4, which supports all Unicode characters, including emojis. // parseTime=True: Tells the driver to automatically parse DATE and DATETIME values into Go's time.Time type. // loc=Local: Uses the local timezone of the server for time-related queries and storage. dsn := fmt.Sprintf( "%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_NAME"), ) db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic("failed to connect database") } sqlDB, err := db.DB() if err != nil { panic("failed to configure database connection") } // Set connection pool settings sqlDB.SetMaxIdleConns(10) sqlDB.SetMaxOpenConns(100) sqlDB.SetConnMaxLifetime(time.Hour) // 1.sqlDB.SetMaxIdleConns(10) // Sets the maximum number of idle (unused but open) connections in the connection pool. // A value of 10 means up to 10 connections can remain idle, ready to be reused. // 2. sqlDB.SetMaxOpenConns(100): // Sets the maximum number of open (active or idle) connections that can be created to the database. // A value of 100 limits the total number of connections, helping to prevent overloading the database. // 3. sqlDB.SetConnMaxLifetime(time.Hour): // Sets the maximum amount of time a connection can be reused before it’s closed. // A value of time.Hour means that each connection will be kept for up to 1 hour, after which it will be discarded and a new connection will be created if needed. DB = db }
バックアップを確認します:
バックアップ ファイルが作成されていることを確認し、そのサイズを確認するか、バックアップ ファイルを開いて必要なデータが含まれていることを確認してください。
バックアップを安全に保存します:
ロールバック プロセス中のデータ損失を防ぐために、バックアップのコピーをクラウド ストレージや別のサーバーなどの安全な場所に保管してください。
Golang を使用し、AWS EKS にデプロイするときに MySQL データをバックアップするには、次の手順に従います。
データベースのバックアップに mysqldump を使用する:
Kubernetes cron ジョブを使用して、MySQL データベースの mysqldump を作成します。
package database import ( "golang-service/models" "golang-service/migrations" "gorm.io/gorm" ) func Migrate(db *gorm.DB) { db.AutoMigrate(&models.User{}) // Apply additional custom migrations if needed }
これを永続ボリュームまたは S3 バケットに保存します。
Kubernetes CronJob で自動化する:
Kubernetes CronJob を使用して、mysqldump プロセスを自動化します。
YAML 設定の例:yaml
package models import "gorm.io/gorm" type User struct { gorm.Model Name string `json:"name"` }
`
AWS RDS 自動バックアップの使用 (RDS を使用している場合):
MySQL データベースが AWS RDS 上にある場合は、RDS の自動バックアップとスナップショットを利用できます。
バックアップの保持期間を設定し、スナップショットを手動で取得するか、Lambda 関数を使用してスナップショットを自動化します。
Velero を使用した永続ボリューム (PV) のバックアップ:
Kubernetes のバックアップ ツールである Velero を使用して、MySQL データを保持する永続ボリュームをバックアップします。
EKS クラスターに Velero をインストールし、S3 にバックアップするように構成します。
これらの方法を使用すると、MySQL データが定期的にバックアップされ、安全に保存されます。
以上がGolang サービスの DB 移行、なぜそれが重要なのか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。