Golang database/sql 패키지 삽질기 - 1편 매개변수 표시자

필자는 주로 자바로 개발해 왔는데 최근 Golang으로 개발하면서 데이터베이스를 다룰 일이 생겼다. Golang에서는 자바의 JDBC와 같은 database/sql 패키지를 제공한다.

이 글은 Golang 초심자로서 필자가 database/sql 패키지를 사용하면서 겪었던 삽질기 중 1편으로 매개변수 표시자Parameter Placeholder에 대한 글이다.


  1. 매개변수 표시자
  2. SQLite 메모리 데이터베이스
  3. 커넥션 풀


Unknown column?

아래는 database/sql 패키지를 사용하여 데이터베이스 parent 테이블에서 id가 '1'인 열의 name 컬럼을 조회하는 코드이다. 데이터베이스로는 SQLite를 사용하고 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
import (
    "database/sql"
    _ "github.com/mattn/go-sqlite3"
    "log"
)
func main() {
    db, err := sql.Open("sqlite3", ":memory:")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    // ...
    var parentName string
    row := db.QueryRow("SELECT name FROM parent WHERE id = $1", 1)
    err = row.Scan(&parentName)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(parentName)
}

코드를 실행해 보면 잘 동작하는 것을 확인할 수 있다.

image2019-5-22_7-44-38

이제 같은 코드를 데이터베이스만 MySQL로 변경해서 실행해 보면 Unknown column 오류를 만난다.

1
2
3
4
5
6
7
8
9
10
package main
import (
   // ...
    _ "github.com/go-sql-driver/mysql"
)
func main() {
    db, err := sql.Open("mysql",
        "root:1111@tcp(127.0.0.1:3306)/article")
    // ...
}

image2019-5-22_7-41-10

왜 같은 코드임에도 불구하고 SQLite는 동작하고 MySQL은 동작하지 않는 걸까? 답은 database/sql 패키지 문서에서 찾을 수 있다.

매개변수 표시자Parameter Placeholder 

Golang에서는 Prepared Statement를 사용할 때 SQL문에 '$1'처럼 대체되는 것을 매개변수 표시자라고 한다. 아래 코드는 '$1' 매개변수 표시자에 실제 값 1로 대체하여 SQL을 실행한다.

1
row := db.QueryRow("SELECT name FROM parent WHERE id = $1", 1)

매개변수 표시자는 문법이 있으니... 데이터베이스마다 다르게 써야 한다는 것이다!

출처 : http://go-database-sql.org/prepared.html

출처 : http://go-database-sql.org/prepared.html

결론

매개변수 표시자를 사용할 때에는 사용하는 데이터베이스마다 다르게 써야 한다. 예시 코드에서는 MySQL로 데이터베이스를 변경했기 때문에 매개변수 표시자를 '?'로 써야 한다. 아래와 같이 변경하고 실행하면 오류 없이 잘 동작한다.

1
row := db.QueryRow("SELECT name FROM parent WHERE id = ?", 1)

참고로 매개변수 표시자 문법에는 언급되어 있지 않지만 SQLite는 '?' 와 '$N'을 모두 수용한다. 따라서 '?'를 써도 SQLite에서 잘 동작한다.

마치며

글을 시작하면서 필자는 주로 자바로 개발을 해왔다고 했다. 자바의 JDBC는 매개변수 표시자를 '?'만 사용한다. 즉 데이터베이스가 달라졌다고 해서 고민할 필요 없다. 드라이버만 변경하면 된다. 이런 경험 때문인지 처음에 오류를 만났을 때 바로 이해하기가 어려웠다.

끝으로 데이터베이스마다 달라지는 매개변수 표시자를 드라이버 수준에서 수용해 주면 좋을 텐데라는 아쉬움이 남는다.


Popit은 페이스북 댓글만 사용하고 있습니다. 페이스북 로그인 후 글을 보시면 댓글이 나타납니다.