我正在使用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)
}