Go语言sql.Open报undefined错误求助及代码问题排查
解决Go语言sql.Open undefined错误的方案
你碰到的这个错误本质是变量名和标准库包名冲突了,咱们一步步来解决:
错误原因分析
在你的main函数里,你定义了一个名为sql的字符串变量:
sql := "SELECT * FROM servers where servername in " + result
这个局部变量会覆盖你导入的database/sql包的引用。当你后续调用sql.Open时,Go编译器会认为你是在这个字符串变量上调用Open方法——而string类型根本没有这个方法,于是就抛出了错误。
修复步骤
重命名冲突的变量
把那个字符串变量改成别的名字,比如query,避免和database/sql包名重复。修正DSN参数
你原来调用sql.Open时传的第二个参数是dbname,这不对,应该用你定义的dsn函数生成正确的数据源连接字符串,也就是dsn(dbname)。
修改后的完整代码
package main import ( "database/sql" "fmt" "io/ioutil" "log" "os" "path/filepath" "runtime" "sort" "strings" _ "github.com/go-sql-driver/mysql" ) const ( username = "" password = "" hostname = "" dbname = "" ) type Server struct { ID int Servername string IP sql.NullString `json:"ip"` OS sql.NullString `json:"os"` } func dsn(dbName string) string { return fmt.Sprintf("%s:%s@tcp(%s)/%s", username, password, hostname, dbName) } func RemoveDuplicates(xs *[]string) { found := make(map[string]bool) j := 0 for i, x := range *xs { if !found[x] { found[x] = true (*xs)[j] = (*xs)[i] j++ } } *xs = (*xs)[:j] } func main() { var TEMPDIR = os.Getenv("HOME") if runtime.GOOS == "windows" { TEMPDIR = "c:\\temp" } filename := filepath.FromSlash(TEMPDIR + "/a.txt") content, err := ioutil.ReadFile(filename) if err != nil { log.Fatal(err) } text := string(content) fmt.Println(text) w := strings.Fields(text) RemoveDuplicates(&w) sort.Strings(w) j := strings.Join(w, "','") result := "('" + j + "')" // 这里把变量名从sql改成query query := "SELECT * FROM servers where servername in " + result fmt.Println("sql: ", query) // 这里调用database/sql的Open,并且传入正确的DSN db, err := sql.Open("mysql", dsn(dbname)) if err != nil { log.Printf("Error %s when opening DB\n", err) return } defer db.Close() log.Printf("Connected to DB\n") }
额外建议(重要)
你现在用字符串拼接的方式生成SQL查询,存在SQL注入风险。更好的做法是使用参数化查询,比如动态生成占位符,然后把切片作为参数传入:
// 生成对应数量的?占位符 placeholders := strings.Repeat("?,", len(w)) placeholders = strings.TrimSuffix(placeholders, ",") query := fmt.Sprintf("SELECT * FROM servers where servername in (%s)", placeholders) // 预处理查询 stmt, err := db.Prepare(query) if err != nil { log.Fatal(err) } defer stmt.Close() // 把w切片转成interface{}切片传入 rows, err := stmt.Query(strings.Fields(text)...) // 后续处理rows...
这样能避免SQL注入,也更符合Go操作数据库的最佳实践。
内容的提问来源于stack exchange,提问作者sfgroups
相关产品推荐
相关产品推荐

