[Golang] JSON 인코딩(Encoding)과 디코딩(Decoding)

Text 기반의 데이터교환 및 전송을 위한 가장 최적화된 표준 포맷으로 JSON을 뽑을 수 있는데요. Go에서는 map이나 struct 타입 객체에 대해 JSON 문자열로 인코딩할 수 있습니다. 여기서 map의 경우에는 그 key의 타입이 string이 아닌 경우 해당 타입을 string으로 변환이 가능할 경우에만 JSON 인코딩이 가능합니다. 다음 코드는 사용자 정의 struct에 대한 map 객체를 인코딩하는 예제입니다.

package main

import (
    "encoding/json"
    "fmt"
)

type Detail struct {
    Age    int
    Active bool
}

func main() {
    mem := map[string]Detail{
        "Alex":    {10, true},
        "Dip2K":   {20, true},
        "Jackass": {15, false},
    }

    jsonBytes, err := json.Marshal(mem)
    if err != nil {
        panic(err)
    }

    jsonString := string(jsonBytes)

    fmt.Println(jsonString)
}

위의 코드를 실행하면 다음과 같은 결과를 볼 수 있습니다.

{"Alex":{"Age":10,"Active":true},"Dip2K":{"Age":20,"Active":true},"Jackass":{"Age":15,"Active":false}}

이제 다시 위에서 얻는 JSON 문자열을 객체로 인코딩해 보도록 하겠습니다. JSON 문자열을 다시 인코딩하기 위해서는 json.Unmarshal 함수를 사용합니다. 예제는 아래와 같습니다.

package main

import (
    "encoding/json"
    "fmt"
)

type Detail struct {
    Age    int
    Active bool
}

func main() {
    jsonString := `
        {
            "Alex":{"Age":10,"Active":true}, 
            "Dip2K":{"Age":20,"Active":true},
            "Jackass":{"Age":15,"Active":false}
        }`

    mem := make(map[string]Detail)
    err := json.Unmarshal([]byte(jsonString), &mem)
    if err != nil {
        panic(err)
    }

    fmt.Println(mem)
    fmt.Println("Dip2K's Active:", mem["Dip2K"].Active)
}

위의 코드에서 14번에 긴 문자열을 jsonString 변수에 담고 있는데요. 긴 문자열을 Go언어에서 입력하기 위한 방식으로 14~19번 코드를 주의해 보시기 바랍니다. 실행 결과는 다음과 같습니다.

map[Dip2K:{20 true} Jackass:{15 false} Alex:{10 true}]
Dip2K's Active: true

[Golang] PostgreSQL 다루기

Golang은 다양한 데이터베이스를 다룰 수 있는데요. Oracle, MySQL, MSSQL Server, DB2 그리고 PostgreSQL 등에 대한 DB 드라이버 라이브러리를 제공합니다. 각 드라이버는 github를 통해 소스코드와 함께 제공되며 드라이버에 대한 라이브러리 소스코드는 go get {URL}처럼 Command Line을 통해 설치하여 사용할 수 있습니다.

이 글은 Local PC에 설치된 PostgreSQL에 연결하여, 이미 존재하는 postgres 데이터베이스의 test 테이블에 데이터를 추가(INSERT)하고 쿼리(SELECT)하는 코드를 설명합니다.

먼저 postgreSQL에 연결하는 코드는 아래와 같습니다.

package main

import (
    "database/sql"
    "fmt"

    _ "github.com/lib/pq"
)

const (
    DB_USER     = "postgres"
    DB_PASSWORD = "ILOVEU"
    DB_NAME     = "postgres"
)

func main() {
    dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable",
        DB_USER, DB_PASSWORD, DB_NAME)

    db, err := sql.Open("postgres", dbinfo)
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // ... 계속

다음 코드는 연결된 DB에 데이터를 추가(INSERT)하는 코드입니다.

    result, err := db.Exec("INSERT INTO test (name, age) VALUES('Jackass', 19)")
    if err != nil {
        panic(err)
    }

    cntAffected, err := result.RowsAffected()
    if err != nil {
        panic(err)
    }

    fmt.Println("Affected Rows:", cntAffected)

    // ... 계속

위의 코드 중 11번은 INSERT 된 데이터의 개수를 나타내며, 여기서는 1개를 추가했으므로 1이 됩니다. 다음 코드는 저장된 데이터를 조회(SELECT)하는 코드입니다.

    rows, err := db.Query("SELECT name, age FROM test")
    if err != nil {
        panic(err)
    }
    defer rows.Close()

    var name string
    var age int
    for rows.Next() {
        err := rows.Scan(&name, &age)
        if err != nil {
            panic(err)
        }

        fmt.Println(name, age)
    }
}	

실행 결과는 다음과 같습니다.

Affected Rows: 1
Dip2K                            40
Dip2K                            40
Jackass                          19
Jackass                          19
Jackass                          19
Jackass                          19
Jackass                          19
Jackass                          19
Jackass                          19