go - 在 GO 中重用数据库连接和 'invalid memory address' 错误

标签 go

我是 GO 的新手,似乎找不到任何关于在全局中重用数据库连接的错误信息。这是导致错误的代码的简化版本:

主要包

import (
    _ "github.com/denisenkom/go-mssqldb"
    "database/sql"
)

var debug = flag.Bool("debug", false, "enable debugging")
var password = flag.String("password", "*****", "the database password")
var port *int = flag.Int("port", 1433, "the database port")
var server = flag.String("server", "localhost", "the database server")
var user = flag.String("user", "*****", "the database user")
var db *sql.DB

func main() {
    // Parse the incoming flags to set variables.
    flag.Parse()

    // Output the database variables if the debug flag is set.
    if *debug {
        fmt.Printf(" password:%s\n", *password)
        fmt.Printf(" port:%d\n", *port)
        fmt.Printf(" server:%s\n", *server)
        fmt.Printf(" user:%s\n", *user)
    }

    // Build out the connection string to the database, and then open the connection to the database.
    connString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d", *server, *user, *password, *port)
    if *debug { fmt.Printf(" connString:%s\n", connString) }
    db, err := sql.Open("mssql", connString)
    if err != nil { log.Fatal("Open connection failed:", err.Error()) }
    err = db.Ping()
    if err != nil {
        fmt.Println("Cannot connect: ", err.Error())
        return
    }

    // Close the connection when we're all done.
    defer db.Close()

    // Truncate the existing records in the ListHubFeed
    res, err := db.Exec( `
        TRUNCATE TABLE foo
    ` )
    _ = res

    if err != nil {
        fmt.Println( "TRUNCATE TABLE failed", err )
    }

    eligible := verifyEligibility( "foo" )

}

func verifyEligibility( email string ) ( success bool ) {

    //Run each check individually, and if any one fails, return false and stop processing additional checks

    // if the routing email is bad, then we can't create an account, so kick it out.
    if( !govalidator.IsEmail( email ) ){
        writeToLog( email )
        return false
    }

    return true;

}

func writeToLog( tolog string ) {
    res, err := db.Exec(`
        INSERT INTO Log ( 
            Email
        ) VALUES (
            ?,
            ?,
            ?,
            ?
        )` , tolog )
    if err != nil {
        fmt.Println( "insert failed", err )
    }
    _ = res
}

那是非常丑陋的伪代码,但重点是 main 中的 TRUNCATE 语句运行得很好,但是在调用 verifyEligibility() 和然后尝试在 writeToLog() 函数中记录条目,我收到以下错误:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x46d485]

goroutine 1 [running]:
database/sql.(*DB).conn(0x0, 0xc082044088, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:634 +0x7b5
database/sql.(*DB).exec(0x0, 0x742730, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:884 +0x9d
database/sql.(*DB).Exec(0x0, 0x742730, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        c:/go/src/database/sql/sql.go:875 +0xd4
main.writeToLog(0xc082004a20, 0x11, 0x70f370, 0x5, 0x0, 0x0, 0x777ef0, 0x24, 0x71ba70, 0x3)

我找不到关于此错误的任何信息,因为它与 go-mssqldb 相关。 db 被声明为全局的,并在 main 中打开,所以我不明白为什么它在 writeToLog() 中对我不可用>.

最佳答案

您的问题是 db 指针在 writeToLog() 函数的上下文中为 nil。罪魁祸首是这一行:

db, err := sql.Open("mssql", connString)

在这里,您将短变量声明运算符 (:=) 与赋值运算符 (=) 混淆了。

此指令使用 db 局部变量覆盖 db 全局变量,只能在您的 main 函数中访问(这称为 阴影,也可以使用包名等)。因此,writeToLog 中使用的 db 变量从未被初始化,因此出现了 nil pointer dereference 错误。

要修复它,您只需修复您的声明,使其成为一种矫揉造作:

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

关于go - 在 GO 中重用数据库连接和 'invalid memory address' 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28965092/

相关文章:

tree - 使用 golang 从表中创建一棵树?

http - 如何在 Go 中使用 application/x-www-form-urlencoded content-type 执行 GET 请求?

go - 如何使用 cursor.ReadDocument() 从 arangodb 读取任意对象

Go 主包分两个文件

templates - 在 Go 模板中请求上下文

docker - 我应该安装什么包而不是 libpcre++-dev 在 Alpine Golang 中使用 C 代码?

google-app-engine - 第三方路由器和静态文件

戈朗 : Send errors using Http Header

json 解码/解码在 json 中没有按预期工作

mysql - Golang 映射多结果