在我正在开发的 REST API 中,有一个/courses
端点以 JSON 格式返回从 SQL 表查询的一些数据。但是,我找不到将查询数据(行)转换为 JSON 的方法。
func GetCoursesEndpoint(w http.ResponseWriter, req *http.Request) {
db, err := sql.Open("mysql", "root:@/academy")
checkErr(err)
rows, err := db.Query("SELECT course_name,price FROM course;")
checkErr(err)
//how to convert returned rows to JSON?
msg, err := json.Marshal(rows)
checkErr(err)
json.NewEncoder(w).Encode(msg)
return
}
Run Code Online (Sandbox Code Playgroud)
该*sql.Rows
类型的实例不能直接编组到 json 中。它没有实现json.Marshaler
接口,并且它的所有字段都未导出,因此无法访问encoding/json
包。
您需要做的是将行的内容扫描到一个可以编组的中间对象中,然后将该对象编组为 json。
所以首先,首先声明一个代表这个“中间”对象的类型,例如:
type Course struct {
Name string
Price int
}
Run Code Online (Sandbox Code Playgroud)
然后,由于您要选择多个记录,您需要使用它的Next
方法迭代行对象,并在每次迭代时将记录的内容扫描到该Course
类型的实例中。
var courses []*Course // declare a slice of courses that will hold all of the Course instances scanned from the rows object
for rows.Next() { // this stops when there are no more rows
c := new(Course) // initialize a new instance
err := rows.Scan(&c.Name, &c.Price) // scan contents of the current row into the instance
if err != nil {
return err
}
courses = append(courses, c) // add each instance to the slice
}
if err := rows.Err(); err != nil { // make sure that there was no issue during the process
return err
}
Run Code Online (Sandbox Code Playgroud)
最后,您可以courses
通过将切片传递给编码器来将切片转换为 json。
if err := json.NewEncoder(w).Encode(courses); err != nil {
log.Println(err)
}
Run Code Online (Sandbox Code Playgroud)
如果您将上述建议应用于您的处理程序,您应该开始看到您期望的结果,或类似的结果……但是,如果您不希望应用程序崩溃,您的处理程序还有一些其他问题需要解决.
第一的:
db, err := sql.Open("mysql", "root:@/academy")
Run Code Online (Sandbox Code Playgroud)
每次执行处理程序时都没有必要打开一个连接,因此如果您将 open-db-connection 代码移到处理程序之外并且只使db
处理程序可以访问该变量会更好。但是,如果您希望每次都保持打开连接,请确保每次也关闭它,否则您将用完可用连接。
第二:
rows, err := db.Query("SELECT course_name,price FROM course;")
Run Code Online (Sandbox Code Playgroud)
返回的rows
对象需要关闭,原因与db
每次打开句柄时都需要关闭句柄的原因相同,即您将用完可用连接并且您的应用程序将崩溃。
因此,应该可以正常工作的更完整的代码版本如下所示:
var db *sql.DB // declare a global variable that will be used by all handlers
func init() {
var err error
db, err = sql.Open("mysql", "root:@/academy") // initialize the global connection
if err != nil {
panic(err)
}
}
type Course struct {
Name string
Price int
}
func GetCoursesEndpoint(w http.ResponseWriter, req *http.Request) {
rows, err := db.Query("SELECT course_name,price FROM course;")
if err != nil {
fmt.Println(err)
return
}
defer rows.Close() // make sure rows is closed when the handler exits
var courses []*Course
for rows.Next() {
c := new(Course)
err := rows.Scan(&c.Name, &c.Price)
if err != nil {
fmt.Println(err)
return
}
courses = append(courses, c)
}
if err := rows.Err(); err != nil {
fmt.Println(err)
return
}
if err := json.NewEncoder(w).Encode(courses); err != nil {
fmt.Println(err)
}
return
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1965 次 |
最近记录: |