2015-05-19 14 views
0

不可用,我有兩個。去文件:a.go和b.gogolang,DB * sql.DB在a.go宣佈b.go

我聲明瞭一個全局DB * sql.DB爲我的MySQL數據庫連接。

我的目標是聲明db一次並在我的所有包文件中使用它,在此例中爲b.go.

一切都建立正常,但打我的API端點/用戶時

22:48:52 app   | 2015/05/18 22:48:52 http: panic serving 127.0.0.1:55742: runtime error: invalid memory address or nil pointer dereference 
goroutine 6 [running]: 
net/http.func·011() 
    /usr/local/go/src/net/http/server.go:1130 +0xbb 
database/sql.(*DB).conn(0x0, 0x4da104, 0x0, 0x0) 
    /usr/local/go/src/database/sql/sql.go:634 +0x7ae 
database/sql.(*DB).query(0x0, 0x809e70, 0x16, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0) 
    /usr/local/go/src/database/sql/sql.go:933 +0x43 
database/sql.(*DB).Query(0x0, 0x809e70, 0x16, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) 
    /usr/local/go/src/database/sql/sql.go:924 +0xa6 
main.GetUsers(0x0, 0x0, 0x0) 
    /var/www/zazok.com/api/src/app/user.go:15 +0xc0 
main.func·001(0xc2080424d0) 
    /var/www/zazok.com/api/src/app/app.go:35 +0x1f 
github.com/gin-gonic/gin.(*Context).Next(0xc2080424d0) 
    /var/www/zazok.com/api/src/github.com/gin-gonic/gin/context.go:114 +0x95 
github.com/gin-gonic/gin.func·006(0xc2080424d0) 
    /var/www/zazok.com/api/src/github.com/gin-gonic/gin/logger.go:49 +0x68 
github.com/gin-gonic/gin.(*Context).Next(0xc2080424d0) 
    /var/www/zazok.com/api/src/github.com/gin-gonic/gin/context.go:114 +0x95 
github.com/gin-gonic/gin.func·009(0x7f1123351408, 0xc208036280, 0xc2080328f0, 0x0, 0x0, 0x0) 
    /var/www/zazok.com/api/src/github.com/gin-gonic/gin/routergroup.go:57 +0xa3 
github.com/julienschmidt/httprouter.(*Router).ServeHTTP(0xc20803af60, 0x7f1123351408, 0xc208036280, 0xc2080328f0) 
    /var/www/zazok.com/api/src/github.com/julienschmidt/httprouter/router.go:299 +0x18e 
github.com/gin-gonic/gin.(*Engine).ServeHTTP(0xc208042000, 0x7f1123351408, 0xc208036280, 0xc2080328f0) 
    /var/www/zazok.com/api/src/github.com/gin-gonic/gin/gin.go:156 +0x4d 
net/http.serverHandler.ServeHTTP(0xc208030120, 0x7f1123351408, 0xc208036280, 0xc2080328f0) 
    /usr/local/go/src/net/http/server.go:1703 +0x19a 
net/http.(*conn).serve(0xc2080361e0) 
    /usr/local/go/src/net/http/server.go:1204 +0xb57 
created by net/http.(*Server).Serve 
    /usr/local/go/src/net/http/server.go:1751 +0x35e 

a.go

package main 

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

var (
    prefix string = "/api/v1" // API prefix 
    db  *sql.DB 
) 

// Boots up this whole thing 
func main() { 
    // Setting up DB 
    db, err := sql.Open("mysql", "root:[email protected](/var/run/mysqld/mysqld.sock)/test.com?collation=utf8_general_ci") 
    if err != nil { 
     panic(err) 
    } 

    defer db.Close() 

    err = db.Ping() 
    if err != nil { 
     panic(err) 
    } 

    r := gin.New() 

    r.Use(gin.Logger()) 

    r.GET(prefix+"/users", func(c *gin.Context) { 

     t := GetUsers() 

     c.JSON(200, t) 
    }) 

    r.Run(":3000") 
} 

b.go

package main 

import (
    "log" 
) 

type User struct { 
    Id   int `json:"id"` 
    Name  string `json:"name"` 
} 

func GetUsers() []User { 
    a := []User{} 

    _, err := db.Query("SELECT name FROM users") 
    if err != nil { 
     log.Fatal(err) 
    } 

    return a 
} 
+0

的[進入全局變量和短期變量定義]可能重複(http://stackoverflow.com/questions/28284138/go-global-variable-and-short -variable-definition) –

回答

1

編輯我得到一個錯誤: 正如DaveC指出的那樣,問題在於你唱歌:=只在本地範圍內啓動一個變量。聲明ERR事先將導致sql.Open保存,而不是創建一個新的地方,在全球的連接,如下所示:

func main() { 
    var err error // <- Declare err 

    // Use = instead of := 
    db, err = sql.Open("mysql", "root:[email protected](/var/run/mysqld/mysqld.sock)/test.com?collation=utf8_general_ci") 
    ... 

此編輯由DaveC,托馬斯和本達內爾(本·達內爾的答案影響:Go global variable and short variable definition

/EDIT

就個人而言,我更喜歡以避免全局儘可能。要做到這一點,改變GetUsers採取參數* sql.DB。然後將您的a.go改爲擁有數據庫接收器的自定義gin.HandlerFunc。在這個例子中,我創建了一個工具結構,您可以使用它來傳入許多「全局」事物。

package main 

import (
    "database/sql" 

    "github.com/gin-gonic/gin" 
    _ "github.com/go-sql-driver/mysql" 
) 

var (
    prefix = "/api/v1" // API prefix 
) 

type tools struct { 
    db *sql.DB 
} 

func (t tools) dispatch() gin.HandlerFunc { 
    return func(c *gin.Context) { 
     GetUsers(t.db) 
    } 
} 

// Boots up this whole thing 
func main() { 
    // Setting up DB 
    db, err := sql.Open("mysql", "root:[email protected](/var/run/mysqld/mysqld.sock)/test.com?collation=utf8_general_ci") 

    if err != nil { 
     panic("DB connection failed") 
    } 
    defer db.Close() 

    t := tools{db} 

    r := gin.New() 

    r.Use(gin.Logger()) 

    r.GET(prefix+"/users", t.dispatch()) 

    r.Run(":3000") 
} 
+0

謝謝!這完美的作品 – Andrey

+0

,並完全忽略了根本原因... –

+0

@DaveC你能澄清?我個人發現,使用結構來傳遞我需要的數據是有利的,而不是聲明全局。爲http的東西創建一個自定義處理函數也是非常可以接受的。我的回答有什麼問題? – vastlysuperiorman

3

我認爲這是一個經典的Go錯誤,它與使用多個文件無關。

本聲明:

db, err := sql.Open("mysql", ...) 

在主範圍內聲明新的變量db(注意:=)和全局變量是不變(無)。

您可以輕鬆地修復它:

var err error 
db, err = sql.Open("mysql", ...)