Go API调用Sql.Query()无返回数据问题求助
问题根源与修复方案
你的代码核心问题是直接将*sql.Rows对象返回并序列化JSON——这完全行不通,*sql.Rows是Go标准库database/sql的底层结果集迭代器,它只是持有查询结果的游标,并没有真正读取数据,也不支持直接JSON序列化。另外你也没有正确关闭结果集,会导致数据库连接泄漏。
修复步骤
1. 完善数据库初始化(添加连接有效性验证)
sql.Open只是创建连接池,不会立即建立连接,所以在初始化时加上Ping验证:
func InitializeDatabase() error { db, err := sql.Open("mysql", dsn(os.Getenv("db_dbname"))) if err != nil { return err } // 验证连接是否真的可用 if err := db.Ping(); err != nil { db.Close() return err } api_db = db return nil }
2. 重写ExecuteCommand,正确读取查询结果
不要直接返回*sql.Rows,而是把结果集读取到可序列化的数据结构中,同时必须关闭结果集防止连接泄漏:
方案一:用结构体映射(类型安全,推荐)
先定义与users表字段匹配的结构体:
// 根据你的实际表字段调整字段名和类型 type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` // 其他字段... }
然后修改ExecuteCommand:
func ExecuteCommand(command string) any { log.Printf("Executing %v\n", command) rows, err := api_db.Query(command) if err != nil { log.Printf("Error %v when executing DB\n", err.Error()) return nil } defer rows.Close() // 确保结果集被关闭 var users []User for rows.Next() { var u User // 注意字段顺序要和SELECT返回的列顺序一致 err := rows.Scan(&u.ID, &u.Name, &u.Email) if err != nil { log.Printf("Failed to scan row: %v", err) continue } users = append(users, u) } // 检查遍历过程中是否出现错误 if err := rows.Err(); err != nil { log.Printf("Row iteration error: %v", err) return nil } return users }
方案二:用动态Map(适合不确定表结构的场景)
如果不想定义结构体,可以用map[string]any存储每行数据:
func ExecuteCommand(command string) any { log.Printf("Executing %v\n", command) rows, err := api_db.Query(command) if err != nil { log.Printf("Error %v when executing DB\n", err.Error()) return nil } defer rows.Close() cols, err := rows.Columns() if err != nil { log.Printf("Failed to get columns: %v", err) return nil } // 准备用于Scan的指针切片 values := make([]any, len(cols)) valuePtrs := make([]any, len(cols)) for i := range values { valuePtrs[i] = &values[i] } var results []map[string]any for rows.Next() { err := rows.Scan(valuePtrs...) if err != nil { log.Printf("Failed to scan row: %v", err) continue } row := make(map[string]any) for i, col := range cols { // 处理NULL值(可选) if values[i] == nil { row[col] = nil } else { row[col] = values[i] } } results = append(results, row) } if err := rows.Err(); err != nil { log.Printf("Row iteration error: %v", err) return nil } return results }
3. 修正控制器的状态码
http.StatusAccepted表示请求已接受但未处理完成,查询成功应该用http.StatusOK:
func MainController(w http.ResponseWriter, r *http.Request) { res := database.ExecuteCommand("SELECT * FROM users;") w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(res) }
额外注意事项
- 禁止直接拼接SQL语句,会引发SQL注入风险,必须使用参数化查询:
api_db.Query("SELECT * FROM users WHERE id = ?", userID) - 可以给连接池配置合理的参数(如
SetMaxOpenConns、SetMaxIdleConns),避免连接泄漏或资源耗尽
内容的提问来源于stack exchange,提问作者Pate
相关产品推荐
相关产品推荐

