///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
๋ค์ ์ ๋ณด๊ฐ ํ์ํฉ๋๋ค.
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, ์๋ฃจ์
์ด ๋ณ์ ๋ฒ์ ์ง์ ์ ๊ดํ ๊ฒ์ด๋ผ๊ณ ์์ํ ์ ์์์ต๋๋ค.
๋๋จํ ๊ฐ์ฌํฉ๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
@methane , ๋น์
db, err = [...]
๋ฅผ ์ค๋ฅ๋ก ์ ์ธํ๋ฉด์db, err := [...]
๋ฅผ ๋ฐ๊ฟ์ผํ์ต๋๋ค. ๋ด ๋์ ์ฐ๋ง ์ค๋ฅ.