Mysql: * sql.DB ์œ ํšจํ•˜์ง€ ์•Š์€ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ ๋˜๋Š” nil ํฌ์ธํ„ฐ ์—ญ ์ฐธ์กฐ

์— ๋งŒ๋“  2013๋…„ 11์›” 02์ผ  ยท  21์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: go-sql-driver/mysql

///Users/jinke/golang/src/cds_spider/common/dbpool/mysql.go ํŒŒ์ผ

package dbpool

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

var DB *sql.DB

func init() {
    db, err := sql.Open("mysql", "root:123456@tcp(192.168.1.20:3306)/?charset=utf8")
    if err != nil {
        panic("dbpool init >> " + err.Error())
    }
    DB = db
    DB.SetMaxIdleConns(5)
}

///Users/jinke/golang/src/cds_spider/newCar/koubei/koubei.go ํŒŒ์ผ

package koubei

import (
    "cds_spider/common/dbpool"
)

type KouBei struct {
    Auto_koubei_id                                               int
    Source                                                       string
    Auto_brand_id, Auto_company_id, Auto_serial_id, Auto_type_id int
    Username                                                     string
    Price                                                        float64
    Province_id, City_id                                         int
    Buy_date, Content, Spider_url, Created                       string
    Level                                                        int
}

func (k *KouBei) Save() (insertID int64, err error) {
    stmt, err := dbpool.DB.Prepare("INSERT mains.koubei SET source=?, auto_brand_id=?, auto_company_id=?, auto_serial_id=?, auto_type_id=?, username=?, price=?, province_id=?, city_id=?, buy_date=?, content=?, level=?, spider_url=?")
    if err != nil {
        return 0, err
    }
    defer stmt.Close()

    res, err := stmt.Exec(k.Source, k.Auto_brand_id, k.Auto_company_id, k.Auto_serial_id, k.Auto_type_id, k.Username, k.Price, k.Province_id, k.City_id, k.Buy_date, k.Content, k.Level, k.Spider_url)
    if err != nil {
        return 0, err
    }
    return res.LastInsertId()
}

"stmt, err : = dbpool.DB.Prepare"๋Š” ์ž˜๋ชป๋œ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ ๋˜๋Š” nil ํฌ์ธํ„ฐ ์—ญ ์ฐธ์กฐ ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค.

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x41 pc=0x52fb5c]

goroutine 2208 [running]:
github.com/go-sql-driver/mysql.(*mysqlConn).writeCommandPacketUint32(0x0, 0x1048eca19, 0xc2046b8330, 0x2ba32ae35a88)
    /Users/jinke/golang/src/github.com/go-sql-driver/mysql/packets.go:327 +0x1c
github.com/go-sql-driver/mysql.(*mysqlStmt).Close(0xc200e3ba50, 0x0, 0x0)
    /Users/jinke/golang/src/github.com/go-sql-driver/mysql/statement.go:24 +0x46
database/sql.(*driverConn).finalClose(0xc2020d5cc0, 0xc20370d900, 0x2bbc7f0)
    /usr/local/go/src/pkg/database/sql/sql.go:285 +0x87
database/sql.funcยท002(0xc2000ca200, 0xc2000aebd0)
    /usr/local/go/src/pkg/database/sql/sql.go:372 +0x2c
database/sql.(*driverConn).Close(0xc2020d5cc0, 0x3, 0x4a173d)
    /usr/local/go/src/pkg/database/sql/sql.go:278 +0x174
database/sql.(*DB).putConn(0xc2000ca1e0, 0xc2020d5cc0, 0x0, 0x0)
    /usr/local/go/src/pkg/database/sql/sql.go:598 +0x2e2
database/sql.(*DB).prepare(0xc2000ca1e0, 0x742450, 0xd2, 0xc20035ba50, 0x85, ...)
    /usr/local/go/src/pkg/database/sql/sql.go:640 +0x267
database/sql.(*DB).Prepare(0xc2000ca1e0, 0x742450, 0xd2, 0x4b2488, 0xc2000ae140, ...)
    /usr/local/go/src/pkg/database/sql/sql.go:608 +0x5a
cds_spider/newCar/koubei.(*KouBei).Save(0xc2046ab790, 0x0, 0x0, 0x0)
    /Users/jinke/golang/src/cds_spider/newCar/koubei/koubei.go:20 +0x6b

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

@methane , ๋‹น์‹  db, err = [...] ๋ฅผ ์˜ค๋ฅ˜๋กœ ์„ ์–ธํ•˜๋ฉด์„œ db, err := [...] ๋ฅผ ๋ฐ”๊ฟ”์•ผํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๋‚˜์œ ์‚ฐ๋งŒ ์˜ค๋ฅ˜.

๋ชจ๋“  21 ๋Œ“๊ธ€

๋‹ค์Œ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • Go-MySQL-Driver ๋ฒ„์ „ (๋˜๋Š” git SHA)
  • Go ๋ฒ„์ „ (์ฝ˜์†”์—์„œ go version ์‹คํ–‰)

go ๋ฒ„์ „ go1.1.2 darwin / amd64
Go-MySQL-Driver๋Š” ์ตœ์‹  ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

์–ด์ œ ๋ฐœํ‘œ ํ•œ ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฆด๋ฆฌ์Šค ์ธ v1.0.3 ์—์„œ๋Š” ํŒจ๋‹‰์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์•„์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค ( go get -๋ช‡ ๋ถ„ ์ดํ›„ ๊ฐ€๋Šฅ).

๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๋” ์กฐ์‚ฌํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์Šคํƒ ํŠธ๋ ˆ์ด์Šค๋Š” ๋‚˜์—๊ฒŒ ์ •๋ง ์ด์ƒํ•˜๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค. ํŒจ๋‹‰์ด ๋•Œ๋ฌธ์— ๋ฐœ์ƒ nil ์— ๋ธํƒ€ ์—ฐ๊ฒฐ stmt.Close (๋ณ€์ˆ˜ mc )๊ฐ€ ์—ฐ๊ฒฐ๋˜์–ด์„œ๋Š” ์•ˆ nil ์ƒ๊ธฐ ์ฝ”๋“œ.

v1.0.3์€ mc == nil ๋จผ์ € ํ™•์ธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์†Œํ•œ nil-pointer ํŒจ๋‹‰์„ ๋ฐฉ์ง€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์˜ค๋ฅ˜๋ฅผ ์žฌํ˜„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x41 pc=0x5304bc]
goroutine 25466 [running]:
github.com/go-sql-driver/mysql.(*mysqlConn).writeCommandPacketUint32(0x0, 0x305e92619, 0xc22b2fe650, 0x2b8b3c6167c0)
    /Users/jinke/golang/src/github.com/go-sql-driver/mysql/packets.go:327 +0x1c
github.com/go-sql-driver/mysql.(*mysqlStmt).Close(0xc22b87a6f0, 0x0, 0x0)
    /Users/jinke/golang/src/github.com/go-sql-driver/mysql/statement.go:24 +0x46
database/sql.(*driverConn).finalClose(0xc202a42780, 0xc2014fd1c0, 0x2210b5a80)
    /usr/local/go/src/pkg/database/sql/sql.go:Jump {0 autohome 25 44 258 1977 hkyjh 12.68 394 397 2011-9-27  http://k.autohome.com.cn/spec/8288/hkyjh 2013-11-02 14:21:38 6}
285 +0x87
database/sql.funcยท002(0xc2000ca200, 0xc2000aebd0)
    /usr/local/go/src/pkg/database/sql/sql.go:372 +0x2c
database/sql.(*driverConn).Close(0xc202a42780, 0x32, 0x9)
    /usr/local/go/src/pkg/database/sql/sql.go:278 +0x174
database/sql.(*DB).putConn(0xc2000ca1e0, 0xc202a42780, 0x0, 0x0)
    /usr/local/go/src/pkg/database/sql/sql.go:598 +0x2e2
database/sql.funcยท004()
    /usr/local/go/src/pkg/database/sql/sql.go:664 +0x41
database/sql.(*DB).exec(0xc2000ca1e0, 0x738330, 0x40, 0x2b8b3c616cb8, 0x2, ...)
    /usr/local/go/src/pkg/database/sql/sql.go:661 +0xb2
database/sql.(*DB).Exec(0xc2000ca1e0, 0x738330, 0x40, 0x2b8b3c616cb8, 0x2, ...)
    /usr/local/go/src/pkg/database/sql/sql.go:650 +0x98
cds_spider/newCar/koubei.AddOk(0x6dee10, 0x8, 0x1, 0x0, 0x0, ...)
    /Users/jinke/golang/src/cds_spider/newCar/koubei/log.go:49 +0x568
cds_spider/newCar/koubei.(*KouBei).Save(0xc20a0a74d0, 0x0, 0x0, 0x0)
    /Users/jinke/golang/src/cds_spider/newCar/koubei/koubei.go:29 +0x3b7
main.funcยท006()
    /Users/jinke/golang/src/cds_spider/newCar/koubei/main/autohome.go:241 +0x37
created by main.funcยท007

/Users/jinke/golang/src/cds_spider/newCar/koubei/log.go

func AddOk(source string, count int) error {
    row := dbpool.DB.QueryRow("SELECT * FROM cheduoshao_spider_status.koubei WHERE source=? AND spider_date=?", source, gcode.Date())
    var (
        id, quantity         int
        sources, spider_date string
    )

    row.Scan(&id, &sources, &quantity, &spider_date)

    if id == 0 {
        stmt, err := dbpool.DB.Prepare("INSERT cheduoshao_spider_status.koubei SET source=?, quantity=?, spider_date=?")
        if err != nil {
            return err
        }
        defer stmt.Close()

        _, err = stmt.Exec(source, 1, gcode.Date())
        if err != nil {
            return err
        }
    } else { 
        dbpool.DB.Exec("UPDATE main.koubei SET quantity=? WHERE id=?", quantity+1, id)
    }

    return nil
}

dbpool.DB.Exec ( "update main.koubei SET ์ˆ˜๋Ÿ‰ =? WHERE id =?", ์ˆ˜๋Ÿ‰ +1, id) ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค.

์ด์ „์— ๊ทธ๋Ÿฐ ์ƒํ™ฉ์„ ์ฐพ์ง€ ๋ชปํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚ด ์‹œ์Šคํ…œ์€ OS X 10.9์ž…๋‹ˆ๋‹ค.

row.Scan(&id, &sources, &quantity, &spider_date) ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
v1.0.3์„ ์‚ฌ์šฉํ•ด ๋ณด์…จ์Šต๋‹ˆ๊นŒ? ๋‚ด๊ฐ€ ๋งํ–ˆ๋“ฏ์ด ์ ์–ด๋„ ํŒจ๋‹‰์€ ํ”ผํ•ด์•ผํ•œ๋‹ค.

๋ช‡ ๋ฒˆ ๋” ํ•ด๋ดค๋Š”๋ฐ, ๊ทธ๋ƒฅ ์˜ˆ์ „ ๋ฒ„์ „์„ ์ง€์šฐ๊ณ , ๋‹ค์‹œ ๊ฐ€์ ธ์™€
๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

err := row.Scan(&id, &sources, &quantity, &spider_date)
    if err != nil {
        return err
    }

์ด ๋ฒ„๊ทธ๋ฅผ ์žฌํ˜„ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ํ•œ ๋ฒˆ์ด ๋ฒ„๊ทธ๋Š” https://codereview.appspot.com/14920046 / Go ๋ฌธ์ œ 5718 (๋˜๋Š” # 98, # 142)๊ณผ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
stmt.Exec ์€ ๋“œ๋ผ์ด๋ฒ„์˜ ์˜ค๋ฅ˜๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์ž˜๋ชป๋œ ์—ฐ๊ฒฐ์„ ํ’€์— ๋‹ค์‹œ ๋„ฃ์Šต๋‹ˆ๋‹ค.

v1.0.3์—๋Š” ์ ์–ด๋„ ํŒจ๋‹‰์„ ํ”ผํ•˜๋Š” # 143์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ์‹œ๊ฐ„ ํ›„์— ์ถœ์‹œ ๋  v1.1์—๋Š” # 151์ด ํฌํ•จ๋˜์–ด์ด ๊ธฐ๋Šฅ์ด ์กฐ๊ธˆ ๋” ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

https://codereview.appspot.com/14920046์„ ์‚ฌ์šฉ ํ•˜์—ฌ Go ๋ฒ„์ „์„ ์ˆ˜๋™์œผ๋กœ ํŒจ์น˜ํ•˜๊ฑฐ๋‚˜์ด ์ˆ˜์ • ์‚ฌํ•ญ์ด ํฌํ•จ ๋œ ๋‹ค์Œ ์•ˆ์ • ๋ฆด๋ฆฌ์Šค๊ฐ€ ๋ฆด๋ฆฌ์Šค ๋  ๋•Œ๊นŒ์ง€ stmt.Exec ํ”ผํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์•„๋งˆ๋„ 2014 ๋…„ 6 ์›”์˜ Go 1.3 ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค ...

์œ„์˜ ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ฐธ๊ณ  ์‚ฌํ•ญ :
stmt ํ•œ ๋ฒˆ๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ์ˆ˜๋™์œผ๋กœ ์ค€๋น„ ํ•  ์ด์œ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. db.Exec ํ•˜์„ธ์š”. stmt.Exec ์ฒ˜๋Ÿผ ๋ฒ„๊ทธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

func AddOk(source string, count int) error {
    var (
        id, quantity         int
        sources, spider_date string
    )
    if err := dbpool.DB.QueryRow("SELECT * FROM cheduoshao_spider_status.koubei WHERE source=? AND spider_date=?", source, gcode.Date()).Scan(&id, &sources, &quantity, &spider_date); err != nil {
        return err
    }

    if id == 0 {
        if _, err =: dbpool.DB.Exec("INSERT cheduoshao_spider_status.koubei SET source=?, quantity=?, spider_date=?", source, 1, gcode.Date()); err != nil {
            return err
        }
    } else { 
        if _, err =: dbpool.DB.Exec("UPDATE main.koubei SET quantity=? WHERE id=?", quantity+1, id); err != nil {
            return err
        }
    }

    return nil
}

์•Œ์•˜์–ด ๊ณ ๋งˆ์›Œ!

๋‚˜๋Š” ๋„ˆ๋ฌด์ด ๋ฌธ์ œ๊ฐ€์žˆ๋‹ค. go ๋ฒ„์ „์€ go1.7.4 linux/amd64 ์ด๊ณ  go-sql-driver๋Š” ์ตœ์‹  ๋ฒ„์ „์ž…๋‹ˆ๋‹ค. AWS์˜ RDS ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:458 (0x42c653)
    gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
/usr/local/go/src/runtime/panic.go:62 (0x42b1ad)
    panicmem: panic(memoryError)
/usr/local/go/src/runtime/sigpanic_unix.go:24 (0x441054)
    sigpanic: panicmem()
/usr/local/go/src/database/sql/sql.go:781 (0x557d0a)
    (*DB).conn: db.mu.Lock()
/usr/local/go/src/database/sql/sql.go:1074 (0x559fbb)
    (*DB).query: ci, err := db.conn(strategy)
/usr/local/go/src/database/sql/sql.go:1062 (0x559dc0)
    (*DB).Query: rows, err = db.query(query, args, cachedOrNewConn)
/home/danilo/Go/src/github.com/DaniloMeritocracy/autocomplete/autocomplete.go:192 (0x402e27)
    _getJSON: rows, err := db.Query(sqlString)
/home/danilo/Go/src/github.com/DaniloMeritocracy/autocomplete/autocomplete.go:130 (0x402b54)
    school: res, err := _getJSON("SELECT * FROM university WHERE LOWER(name) LIKE '" + strings.Replace(term, "'", "\\'", -1) + "%' LIMIT 15")
/home/danilo/Go/src/github.com/DaniloMeritocracy/autocomplete/autocomplete.go:56 (0x403985)
    main.func1: results = school(term)
/home/danilo/Go/src/gopkg.in/gin-gonic/gin.v1/context.go:97 (0x45d53a)
    (*Context).Next: c.handlers[c.index](c)
/home/danilo/Go/src/gopkg.in/gin-gonic/gin.v1/recovery.go:45 (0x46d31a)
    RecoveryWithWriter.func1: c.Next()
/home/danilo/Go/src/gopkg.in/gin-gonic/gin.v1/context.go:97 (0x45d53a)
    (*Context).Next: c.handlers[c.index](c)
/home/danilo/Go/src/gopkg.in/gin-gonic/gin.v1/logger.go:72 (0x46c40f)
    LoggerWithWriter.func1: c.Next()
/home/danilo/Go/src/gopkg.in/gin-gonic/gin.v1/context.go:97 (0x45d53a)
    (*Context).Next: c.handlers[c.index](c)
/home/danilo/Go/src/gopkg.in/gin-gonic/gin.v1/gin.go:284 (0x4638ce)
    (*Engine).handleHTTPRequest: context.Next()
/home/danilo/Go/src/gopkg.in/gin-gonic/gin.v1/gin.go:265 (0x4631b0)
    (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2202 (0x4e1fdd)
    serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1579 (0x4de947)
    (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:2086 (0x45c0f1)
    goexit: BYTE    $0x90   // NOP

๋‹ค์Œ์€ ๊ฒฐ๊ณผ์˜ JSON ์ธ์ฝ”๋”ฉ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” _getJSON ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

func _getJSON(sqlString string) (string, error) {
    rows, err := db.Query(sqlString)
    if err != nil {
        return "", err
    }
    defer rows.Close()
    columns, err := rows.Columns()
    if err != nil {
        return "", err
    }
    count := len(columns)
    tableData := make([]map[string]interface{}, 0)
    values := make([]interface{}, count)
    valuePtrs := make([]interface{}, count)
    for rows.Next() {
        for i := 0; i < count; i++ {
            valuePtrs[i] = &values[i]
        }
        rows.Scan(valuePtrs...)
        entry := make(map[string]interface{})
        for i, col := range columns {
            var v interface{}
            val := values[i]
            b, ok := val.([]byte)
            if ok {
                v = string(b)
            } else {
                v = val
            }
            entry[col] = v
        }
        tableData = append(tableData, entry)
    }
    jsonData, err := json.Marshal(tableData)
    if err != nil {
        return "", err
    }
    //fmt.Println(string(jsonData))
    return string(jsonData), nil
}

@DaniloPolani ๊ท€ํ•˜์˜ db๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์™œ nil์ด์–ด์•ผํ•ฉ๋‹ˆ๊นŒ? var db *sql.DB ํ•จ์ˆ˜ ์™ธ๋ถ€์— db var๊ฐ€ ์žˆ๊ณ  ์ฃผ ํ•จ์ˆ˜์—์„œ ์—ฐ๊ฒฐ์„ ์—ด์—ˆ์Šต๋‹ˆ๋‹ค.

db, err := sql.Open("mysql", "<USERNAME>:<PASSWORD>@tcp(<HOST>:3306)/<DB_NAME>")
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()

๊ทธ๋Ÿฐ ๋‹ค์Œ _getJSON() ์—์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ž๊ฒฉ ์ฆ๋ช…์€ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. AWS ๋ฌธ์ œ์ผ๊นŒ์š”? ๋‚˜๋Š” localhost๋กœ ์‹œ๋„ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

db, err := sql.Open("mysql", "<USERNAME>:<PASSWORD>@tcp(<HOST>:3306)/<DB_NAME>")

๊ทธ๋Ÿฌ๋ฉด db๋Š” ์ „์—ญ ๋ณ€์ˆ˜ _getJSON() ์•„๋‹Œ main์˜ ๋กœ์ปฌ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค.

์™„๋ฒฝํ•˜๊ฒŒ ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด๋„ ์ง€์  ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
์ฝ”๋“œ์— ๊ฒฝ์Ÿ ์กฐ๊ฑด์ด ์žˆ์Šต๋‹ˆ๋‹ค.
go build -race ๋Š” ๋‹น์‹ ์˜ ์นœ๊ตฌ์ž…๋‹ˆ๋‹ค.

@methane , ๋‹น์‹  db, err = [...] ๋ฅผ ์˜ค๋ฅ˜๋กœ ์„ ์–ธํ•˜๋ฉด์„œ db, err := [...] ๋ฅผ ๋ฐ”๊ฟ”์•ผํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๋‚˜์œ ์‚ฐ๋งŒ ์˜ค๋ฅ˜.

๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ์— ๋†€๋ž์Šต๋‹ˆ๋‹ค.
@danilopolani์˜ ์†”๋ฃจ์…˜์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@Danilopolani @methane ๋„ˆํฌ๋“ค์€ ๋‚ด ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ–ˆ์Šต๋‹ˆ๋‹ค

@danilopolani ๋‹น์‹ ์ด ๋งž์Šต๋‹ˆ๋‹ค, ๋‹น์‹ ์˜ ๋„์›€์— ๋Œ€๋‹จํžˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค, ๋‚˜๋Š” ์˜ค๋žซ๋™์•ˆ์ด ๋ฌธ์ œ๋ฅผ ์ฐพ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค .. @danilopolani ์†”๋ฃจ์…˜์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค @methane @danilopolani ์ €๋„ ๊ฐ™์€ ์‹ค์ˆ˜๋ฅผ ์ €์งˆ๋ €์Šต๋‹ˆ๋‹ค.

OMG, ์†”๋ฃจ์…˜์ด ๋ณ€์ˆ˜ ๋ฒ”์œ„ ์ง€์ •์— ๊ด€ํ•œ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.
๋Œ€๋‹จํžˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰