Golang MySQL 数据库未选择

huangapple go评论100阅读模式
英文:

Golang MySQL Database Not Selected

问题

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

英文:

I'm using github.com/go-sql-driver/mysql package to connect to MySQL. It works well except when I select a database (USE), I can't run queries against it.

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())
	}
}

The program produces this output:

Error 1046: No database selected

答案1

得分: 9

在sql.Open函数的DSN(数据源名称)部分直接指定数据库:

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

Specify the database directly in the DSN (Data Source Name) part of the sql.Open function:

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

答案2

得分: 3

这是要翻译的内容:

这是因为db维护了一个连接池,其中有几个连接到mysql数据库。"USE test"只是让一个连接使用test模式。

当你稍后进行数据库查询时,驱动程序会选择一个空闲连接,如果选择了使用test模式的连接,一切正常,但如果选择了另一个连接,它就不会使用test模式,因此会报错:没有选择数据库。

如果你添加以下语句:

db.SetMaxOpenConns(1)

db将只维护一个连接,就不会出错。当然,在高并发场景下这是不可能的。

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

英文:

That's because db maintains a connection pool that has several connections to mysql database."USE test" just let one connection use schema test.
When you do database query later,the driver will select one idle connection,if the connection that use test schema is selected,it will be normal,but if another connection is chosen, it does not use test,so it will report an error:no database selected.

If you add a clause:

db.SetMaxOpenConns(1)

the db will maintain only one connection,it will not have an error.And of course it's impossible in high concurrency scene.

If you specify the database name in sql.open() function,all the connection will use this data base which can avoid this problem.

答案3

得分: 1

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

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

对于SELECT/UPDATE/INSERT等,需要在查询中指定数据库名称。

英文:

In your case you need to use transactions:

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

For SELECT/UPDATE/INSERT/etc need to specify DB name in the query.

答案4

得分: 1

正如其他答案提到的那样,sql.DB不是单个连接,而是一个连接池。当你执行use database时,可以想象你在连接池中的一个连接上执行了查询。下一个查询将从连接池中获取另一个连接,该连接没有选择任何数据库。

我强烈建议不要使用事务来实现这个(正如一些地方建议的那样)。

我建议使用上下文(context):

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)
}
英文:

As other answers mentioned, sql.DB is not a single connection but a connection pool. When you execute use database, imagine you executed your query on just one connection in the pool. Next query will get another connection from the pool which has no databases selected.

I would strongly advise against using transactions for this (as several places suggest).

I would suggest to use context:

	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)
	}

huangapple
  • 本文由 发表于 2013年11月12日 19:26:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/19927879.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定