未选择 Golang MySQL 数据库



我正在使用github.com/go-sql-driver/mysql包连接到MySQL。它运行良好,除非我选择一个数据库(USE),我无法对它运行查询。

package main
import (
    "database/sql"
    "fmt"
    "log"
)
import _ "github.com/go-sql-driver/mysql"
func main() {
    dsn := "root:@/"
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        fmt.Println("Failed to prepare connection to database. DSN:", dsn)
        log.Fatal("Error:", err.Error())
    }
    err = db.Ping()
    if err != nil {
        fmt.Println("Failed to establish connection to database. DSN:", dsn)
        log.Fatal("Error:", err.Error())
    }
    _, err = db.Query("USE test")
    if err != nil {
        fmt.Println("Failed to change database.")
        log.Fatal("Error:", err.Error())
    }
    _, err = db.Query("SHOW TABLES")
    if err != nil {
        fmt.Println("Failed to execute query.")
        log.Fatal("Error:", err.Error())
    }
}

程序生成以下输出:

Error 1046: No database selected

直接在 sql 的 DSN(数据源名称)部分中指定数据库。打开功能:

dsn := "user:password@/dbname"
db, err := sql.Open("mysql", dsn)

这是因为数据库维护着一个连接池,该连接池与mysql数据库有多个连接。USE test"只让一个连接使用架构测试。当你稍后做数据库查询时,驱动会选择一个空闲连接,如果选择了使用测试模式的连接,那将是正常的,但如果选择了另一个连接,它不使用test,所以它会报告一个错误:没有选择数据库。

如果添加子句:

db.SetMaxOpenConns(1)

数据库将只保持一个连接,不会有错误。当然,在高并发场景中这是不可能的。

如果在sql.open()函数中指定数据库名称,则所有连接都将使用此数据库,这可以避免此问题。

在您的情况下,您需要使用事务:

tx, _ := db.Begin()
tx.Query("USE test")
tx.Query("SHOW TABLES")
tx.Commit()

对于选择/更新/插入/等,需要在查询中指定数据库名称。

正如其他答案所提到的,sql.DB不是单个连接,而是一个连接池。当您执行 use database 时,假设您只在池中的一个连接上执行了查询。下一个查询将从未选择数据库的池中获取另一个连接。

我强烈建议不要为此使用交易(正如一些地方所建议的那样)。

我建议使用上下文:

    ctx := context.Background()
    conn, err := db.Conn(ctx)
    conn.ExecContext(ctx, "use mydb")
    defer conn.Close()
    var found int
    err = conn.QueryRowContext(ctx, "SELECT count(*) as found FROM mytable").Scan(&found)
    if err != nil {
        panic(err)
    }

最新更新