본문 바로가기
개발/Golang

GORM 맛보기 1 - 퀵스타트

by 상5c 2021. 8. 29.

이 글은 공식 홈페이지의 Quick Start 가이드에 설명을 덧붙이는 형태로 작성되었다.

ORM이란?

  • Object Relation mapping.
  • 객체와 db를 매핑해주는 것.
  • 매핑된 정보를 바탕으로 자동으로 SQL을 생성해준다.
  • 자세히 설명된 블로그가 있어 링크로 대체한다.

Golang의 ORM

  • 과거에는 XORM(솜)을 사용했으며 현재는 GORM(곰)이 많이 사용되는 것으로 보인다.

Quick start

  • gorm 공식 홈페이지에서 제공하는 quick start를 약간 변형하여 사용했다.
  • db는 docker postgresql을 사용하였다.
docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=1234 -d postgres
package main

import (
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
)

type Product struct {
  gorm.Model
  Code  string
  Price uint
}

func main() {
    dsn := "host=localhost user=postgres password=1234 dbname=postgres port=5432 sslmode=disable TimeZone=Asia/Seoul"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
        Logger: logger.Default.LogMode(logger.Info),
    })  
    if err != nil {
    panic("Db 연결에 실패하였습니다.")
  }

  // 테이블 자동 생성
  db.AutoMigrate(&Product{})

  // 생성
  db.Create(&Product{Code: "D42", Price: 100})

  // 읽기
  var product Product
  db.First(&product, 1) // primary key기준으로 product 찾기
  db.First(&product, "code = ?", "D42") // code가 D42인 product 찾기

  // 수정 - product의 price를 200으로
  db.Model(&product).Update("Price", 200)
  // 수정 - 여러개의 필드를 수정하기
  db.Model(&product).Updates(Product{Price: 200, Code: "F42"})
  db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})

  // 삭제 - product 삭제하기
  db.Delete(&product, 1)
}

한줄씩 뜯어보기

데이터베이스 연결

    dsn := "host=localhost user=postgres password=1234 dbname=postgres port=5432 sslmode=disable TimeZone=Asia/Seoul"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
        Logger: logger.Default.LogMode(logger.Info),
    })
  • postgres db에 연결하는 부분이다. config는 말 그대로 데이터베이스 연결과 관련된 설정을 할 수 있는데, logmode를 logger.info로 설정해주면 실행되는 모든 SQL문을 로그로 확인할 수 있다.

테이블 자동 생성

type Product struct {
   gorm.Model
   Code  string
   Price uint
}

db.AutoMigrate(&Product{})
  • 구조체의 필드 값으로 테이블을 생성한다. default 값을 지정해줄 수 있으며, 지정하지 않은 경우 zero-value가 사용된다.
  • gorm.Model을 포함하고 있는데 Model 구조체는 아래와 같이 생겼으며, 데이터 CRUD시에 gorm이 create, udpate, deleted 값을 넣어준다.
type Model struct {
    ID uint `gorm:"primarykey"` 
    CreatedAt time.Time 
    UpdatedAt time.Time 
    DeletedAt DeletedAt `gorm:"index"` 
}

 

CREATE

db.Create(&Product{Code: "D42", Price: 100})
// INSERT INTO "products" ("created_at","updated_at","deleted_at","code","price") VALUES ('2021-08-29 21:41:13.781','2021-08-29 21:41:13.781',NULL,'D42',100) RETURNING "id"**
  • 객체를 받아 테이블에 저장한다.
  • 필드를 지정하고 싶으면 Select, Omit을 사용한다.
db.Select("필드명", ...).Create(...) 
// INSERT INTO "테이블" ("필드명") VALUES ("...") 
db.Omit("제외할 필드명", ...).Create(...) 
// INSERT INTO "테이블" ("Omit에 전달한 필드를 제외한 필드", ...) VALUES ("...")

 

READ

p := &Product{}

db.First(&p) // select * from table limit 1
db.Last(&p) // select * from table order by desc limit 1
  • 쿼리를 실행한 결과를 p에 담는다.

조건을 지정하는 경우

db.Where("필드명 = ?", "값").First(&p)

이외에도 직관적인 여러 메소드를 메소드 체이닝으로 사용할 수 있다.

db.Where().Or().Not().Limit().Offset().Order().Group().Having().Find()

UPDATE

GORM은 아쉽게도 Dirty Checking 기능이 없다.

// 수정 - product의 price를 200으로
db.Model(&product).Update("Price", 200)

// 풀어쓴 형태
db.First(&product**)
product.Price = 200
db.Save(&product)
  • 값을 변경한 후 Save() 메소드를 사용하여 저장해 준다.

DELETE

db.Where("price = ?", 122).Delete(&Product{})
// UPDATE "products" SET "deleted_at"='2021-08-29 22:04:44.911' WHERE price = 122 AND "products"."deleted_at" IS NULL
  • soft delete가 실행된다.

마무리

GORM 기본 사용법에 대해 가볍게 정리해 보았다. GORM은 Java의 Hibernate에 비해 덜 깔끔하고 덜 친절하다고 느꼈다.

GORM 관련 글을 시리즈 형태로 작성해 보려 하는데 아마 다음 글은 연관관계 매핑과 관련된 글이 될 것 같다. GORM에서는 1:1, 1:N과 같은 연관관계를 어떻게 표현했는지, N+1 문제를 어떻게 해결할 수 있는지 알아볼 계획이다.