Golang으로 마이그레이션을 사용하는 방법

Linda Hamilton
풀어 주다: 2024-11-09 07:28:02
원래의
869명이 탐색했습니다.

golang- migration 사용 방법을 보여주는 간단한 샘플 애플리케이션

마이그레이션을 사용해야 하는 이유는 무엇인가요?

많은 사람들이 이 질문을 하며 저는 마이그레이션 사용의 주요 이점을 강조하기 위해 이 목록을 만들려고 노력했습니다.

버전 관리: 가장 중요하고 중요한 것 중 하나는 데이터베이스 스키마의 다양한 수정 사항을 버전 관리할 수 있다는 것입니다. 마이그레이션이 없으면 이러한 스키마 변경 사항은 일관되지 않고 추적이 불가능하여 버전 관리 문제와 오류가 발생할 수 있습니다.

롤백: 장애가 발생할 경우를 대비해 항상 롤백 시스템을 갖추는 것이 필요합니다. 마이그레이션 시스템에는 항상 데이터베이스에 변경 사항을 적용하는 방법과 변경 사항을 빠르고 일관되게 되돌리는 방법 두 가지가 있습니다. :-)

자동화 및 CI/CD 통합: 마이그레이션을 자동화하여 CI/CD 파이프라인의 일부로 사용할 수 있습니다. 이는 수동 개입 없이 변경 사항을 원활하고 일관되게 배포하는 데 도움이 됩니다.

더 많은 장점을 찾을 수 있지만 이 점이 주요 장점을 잘 요약한 것이라고 생각합니다.

Golang에서 마이그레이션을 구현하는 방법은 무엇입니까?

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
로그인 후 복사
로그인 후 복사
로그인 후 복사

간단한 golang 앱 만들기

성공적인 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()
 }
}
로그인 후 복사
로그인 후 복사
로그인 후 복사

실행하면 비슷한 결과가 나옵니다.

How to use migrations with Golang

CLI 마이그레이션

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
로그인 후 복사
로그인 후 복사
로그인 후 복사
  • ext: 생성할 파일의 확장자입니다.
  • dir: 마이그레이션이 생성될 디렉터리입니다.
  • seq: 마이그레이션 시퀀스 이름입니다.

이 명령은 데이터베이스/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
로그인 후 복사
  • 경로: 마이그레이션 디렉터리의 경로입니다.
  • 데이터베이스: 데이터베이스 DSN 연결을 정의합니다.

참고 : 마이그레이션을 처음 실행할 때 마이그레이션이 적용된 버전 번호를 알고 있는 "schema_migrations" 테이블이 생성됩니다.

그리고 Golang 애플리케이션을 실행하여 결과를 표시합니다.

How to use migrations with 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 애플리케이션에서 실행하면 새로운 필드를 볼 수 있습니다:

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라는 두 가지 변형을 볼 수 있습니다.

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿