golang- migration 사용 방법을 보여주는 간단한 샘플 애플리케이션
많은 사람들이 이 질문을 하며 저는 마이그레이션 사용의 주요 이점을 강조하기 위해 이 목록을 만들려고 노력했습니다.
버전 관리: 가장 중요하고 중요한 것 중 하나는 데이터베이스 스키마의 다양한 수정 사항을 버전 관리할 수 있다는 것입니다. 마이그레이션이 없으면 이러한 스키마 변경 사항은 일관되지 않고 추적이 불가능하여 버전 관리 문제와 오류가 발생할 수 있습니다.
롤백: 장애가 발생할 경우를 대비해 항상 롤백 시스템을 갖추는 것이 필요합니다. 마이그레이션 시스템에는 항상 데이터베이스에 변경 사항을 적용하는 방법과 변경 사항을 빠르고 일관되게 되돌리는 방법 두 가지가 있습니다. :-)
자동화 및 CI/CD 통합: 마이그레이션을 자동화하여 CI/CD 파이프라인의 일부로 사용할 수 있습니다. 이는 수동 개입 없이 변경 사항을 원활하고 일관되게 배포하는 데 도움이 됩니다.
더 많은 장점을 찾을 수 있지만 이 점이 주요 장점을 잘 요약한 것이라고 생각합니다.
Go는 해당 제안에 대해 기본적으로 마이그레이션을 지원하지 않습니다. 인기 있는 golang- migration 패키지를 사용할 수도 있고 GORM과 같은 ORM을 사용하는 경우에도 마이그레이션을 사용할 수 있습니다.
두 패키지 모두 매우 인기가 있지만 이 예에서는 ORM 구현에 관심이 없기 때문에 golang- migration을 사용하겠습니다.
간단한 애플리케이션을 구현하여 어떻게 사용되는지 단계별로 살펴보겠습니다.
이 문서를 따르려면 Go와 Docker Compose가 포함된 Docker가 필요합니다
좋아하는 DB를 정의할 루트 디렉터리에 docker-compose.yml 파일을 만듭니다. 제 경우에는 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
성공적인 DB 연결을 보장하고 데이터베이스의 모든 테이블과 구조를 해당 구조와 함께 나열하기 위해 간단한 golang 애플리케이션을 만듭니다. 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-마이그레이션 CLI를 실행하려면 기본적으로 CLI를 로컬에 설치하거나 공식 Docker 이미지를 통해 실행하는 두 가지 방법(마이그레이션/마이그레이션)이 있습니다.
개인적으로 저는 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
이 명령은 데이터베이스/migrations/ 폴더에 000001createuserstable.up.sql 및 000001createuserstable.down.sql이라는 두 개의 빈 파일을 생성합니다
000001createuserstable.up.sql 파일에서 사용자 테이블 생성을 위한 SQL을 정의합니다.
DATABASE_DSN=root:root@tcp(localhost:3306)/app
000001createuserstable.down.sql 파일에서 up의 모든 변경 사항을 되돌리도록 SQL을 정의합니다. 이 경우 사용자 테이블을 삭제해야 합니다.
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 애플리케이션을 실행하여 결과를 표시합니다.
사용자 테이블에 새 컬럼폰 추가
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라는 두 가지 변형을 볼 수 있습니다.
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 중국어 웹사이트의 기타 관련 기사를 참조하세요!