Mysql 在Go中将SQL行转换为JSON格式
在我正在开发的RESTAPI中,有一个Mysql 在Go中将SQL行转换为JSON格式,mysql,rest,go,Mysql,Rest,Go,在我正在开发的RESTAPI中,有一个/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 cour
/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
}
该类型的实例不能直接封送到json中。它不实现json.Marshaler
接口,其所有字段都未报告,因此encoding/json
包无法访问
您需要做的是将行的内容扫描到一个可以封送的中间对象中,然后将该对象封送到json中
首先,声明一个表示这个“中间”对象的类型,例如:
type Course struct {
Name string
Price int
}
然后,由于要选择多条记录,因此需要使用其Next
方法迭代rows对象,并在每次迭代时将记录的内容扫描到课程
类型的实例中
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
}
最后,您可以将courses
片段传递给编码器,从而将其转换为json
if err := json.NewEncoder(w).Encode(courses); err != nil {
log.Println(err)
}
如果你将上述建议应用到你的处理程序中,你应该开始看到你期望的结果,或者类似的结果。。。但是,如果不希望应用程序崩溃,处理程序还有一些其他问题需要解决 第一:
db, err := sql.Open("mysql", "root:@/academy")
每次执行处理程序时都不需要打开连接,因此,如果将open db connection代码移到处理程序之外,只让处理程序可以访问db
变量,效果会更好。但是,如果希望每次都继续打开连接,则必须确保每次都关闭连接,否则将耗尽可用的连接
第二:
rows, err := db.Query("SELECT course_name,price FROM course;")
返回的行
对象需要关闭,原因与每次继续打开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
}