GoLang:数据库失去范围

时间:2015-05-04 15:52:04

标签: mysql database go scope

Go to Go,来自.Net-land所以请耐心等待...在管理和重用数据库连接方面,特别喜欢构建我的Go应用程序的一些指导。

我已将我的db代码拆分为一个包,以允许db-lookups进入处理sql查找的包,如存储库层。我希望能够灵活地将我的数据库层与我的应用服务分离,因此我可以在必要时轻松替换我的数据库。

基本上我正在寻找关于如何以及何时处理sql连接并在应用程序中持有sql.DB指针的一些指导。我需要在main.go中保留一个全局指针,还是可以管理我的mysql包中的连接?

这是我的代码:

package mysqlstorage

import (
    "database/sql"
    "fmt"
    "log"
    "types"
)

var db *sql.DB

func Connect() {
    db, dberr := sql.Open(“<CONNECTION_STRING>“)

    if dberr != nil {
        fmt.Println(dberr)
    }
}

func SaveUser(u types.User) {
    // use db here! 
    ....
}

func GetUser(id string) types.User {
    // use db here!
    ....
}

在运行我的main.go并使用我的userservices包尝试保存用户时,我遇到了一个问题,我似乎失去了指针的范围: -

2015/05/03 17:49:08 http: panic serving [::1]:50106: runtime error: invalid memory address or nil pointer dereference goroutine 7 [running]: net/http.func·011() 
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1130 +0xbb database/sql.(*DB).conn(0x0, 0x10, 0x0, 0x0)   
/usr/local/Cellar/go/1.4.2/libexec/src/database/sql/sql.go:634 +0x7ae database/sql.(*DB).Ping(0x0, 0x0, 0x0)    
/usr/local/Cellar/go/1.4.2/libexec/src/database/sql/sql.go:462 +0x3a mysqlstorage.SaveUser(0x0, 0xc20805425a, 0x7, 0xc208054280, 0x11, 0xc208054268, 0x6, 0xc208054274, 0x5)    
/Users/<USERNAME>/Desktop/go/<APPNAME>/api/src/mysqlstorage/mysqlstorage.go:24
    +0x35 services.CreateUser(0x57c148, 0xc2080563c0, 0xc2080329c0)     
/Users/<USERNAME>/Desktop/go/<APPNAME>/api/src/services/userservices.go:30
    +0x398 net/http.HandlerFunc.ServeHTTP(0x3d02a0, 0x57c148, 0xc2080563c0, 0xc2080329c0)   
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1265 +0x41 github.com/gorilla/mux.(*Router).ServeHTTP(0xc20803c140, 0x57c148, 0xc2080563c0, 0xc2080329c0)     
/Users/<USERNAME>/Desktop/go/<APPNAME>/api/src/github.com/gorilla/mux/mux.go:98
    +0x297 net/http.(*ServeMux).ServeHTTP(0xc20803a720, 0x57c148, 0xc2080563c0, 0xc2080329c0)   
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1541 +0x17d net/http.serverHandler.ServeHTTP(0xc2080543c0, 0x57c148, 0xc2080563c0, 0xc2080329c0)  
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1703 +0x19a net/http.(*conn).serve(0xc208056320)  
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1204 +0xb57 created by net/http.(*Server).Serve   
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1751 +0x35e

任何指导都会表示赞赏!谢谢你们!

2 个答案:

答案 0 :(得分:3)

由于您使用db运算符,我认为您的问题是Connect()范围内的:=shadowed。如果您更改方法以声明dberr var:

func Connect() {
    var dberr error
    db, dberr = sql.Open(“<CONNECTION_STRING>“)

    if dberr != nil {
        fmt.Println(dberr)
    }
}

您的代码将按预期工作

答案 1 :(得分:2)

正如@Lander所指出的那样,你的超出范围是因为你正在通过db, err :=赋值创建一个局部变量db,当Connect func返回时,它会超出范围。

一般使用sql.DB

来自database/sql package

  

DB是一个表示零个或多个底层连接池的数据库句柄。多个goroutine可以安全地同时使用。

     

sql包自动创建并释放连接;它还维护一个空闲连接池。

  

返回的数据库可以安全地由多个goroutine并发使用,并维护自己的空闲连接池。因此,Open函数应该只调用一次。很少需要关闭数据库。

那就是说你要打开一次连接,然后在整个过程中保持打开状态。有了它,当你完成(或遇到致命或恐慌)时,实际关闭它的唯一可靠方法是在打开之后立即执行惯用go defer db.Close(),这需要在main函数中完成。

您仍然可以将Connect函数保存在包中,并使用它来初始化全局包变量db,但是从main调用它并将* sql.DB返回main,这样就可以推迟db.Close()。< / p>