英文:
channel of type interface not receiving value in golang with MySql
问题
我是你的中文翻译助手,以下是你提供的代码的翻译:
package main
import (
"database/sql"
"fmt"
"net/http"
_ "github.com/go-sql-driver/mysql"
"log"
)
var db *sql.DB
func getdataList(id int) {
ch := make(chan interface{})
done := make(chan bool)
RunQuery(ch, "select id,name, last_name,first_name from persons where id= ?", id)
go func() {
for {
x, ok := <-ch // 在这里我没有收到任何数据
if ok {
fmt.Println(x)
} else {
fmt.Println("done")
done <- true
return
}
}
}()
}
func RunQuery(ch chan interface{}, query string, param interface{}) {
stmt, err := db.Prepare(query)
if err != nil {
panic(err.Error())
}
defer stmt.Close()
rows, err := stmt.Query(param)
columns, err := rows.Columns()
if err != nil {
fmt.Println("Failed to get columns", err)
return
}
count := len(columns)
tableData := make([]map[string]interface{}, 0)
values := make([]interface{}, count)
valuePtrs := make([]interface{}, count)
for rows.Next() {
for i := 0; i < count; i++ {
valuePtrs[i] = &values[i]
}
rows.Scan(valuePtrs...)
entry := make(map[string]interface{})
for i, col := range columns {
var v interface{}
val := values[i]
b, ok := val.([]byte)
if ok {
v = string(b)
} else {
v = val
}
entry[col] = v
}
tableData = append(tableData, entry)
}
fmt.Println(tableData) // 在这里我收到了map中的数据
ch <- tableData
}
func dbtest(w http.ResponseWriter, req *http.Request) {
go getdataList(2)
go getdataList(3)
}
func main() {
var err error
db, err = sql.Open("mysql", "root:@/dbName")
if err != nil {
panic(err.Error())
}
defer db.Close()
http.HandleFunc("/dbTest", dbtest)
log.Fatal(http.ListenAndServe(":8080", nil))
}
请注意,我只翻译了你提供的代码部分,其他内容不包括在内。如果你有任何问题,请随时提问。
英文:
I am new to golang. I am trying to do concurrent queries to mysql db with golang. I know channels can be of the type interface. When I print tableData (type map)
in RunQuery
function I am getting the result. I am sending tableData
to ch
i.e. channel of type interface. In function getdataList
I am not getting any value in ch
. I don't understand what I am doing wrong.
Following is my code:
package main
import (
"database/sql"
"fmt"
"net/http"
_ "github.com/go-sql-driver/mysql"
"log"
)
var db *sql.DB
func getdataList(id int) {
ch := make(chan interface{})
done := make (chan bool)
RunQuery(ch,"select id,name, last_name,first_name from persons where id= ?", id)
go func() {
for {
x, ok := <-ch //I am not getting any data in channel here
if ok {
fmt.Println(x)
}else {
fmt.Println("done")
done <- true
return
}
}
}()
}
func RunQuery (ch chan interface{}, query string, param interface{}) {
stmt, err := db.Prepare(query)
if err != nil {
panic(err.Error())
}
defer stmt.Close()
rows, err := stmt.Query(param)
columns, err := rows.Columns()
if err != nil {
fmt.Println("Failed to get columns", err)
return
}
count := len(columns)
tableData := make([]map[string]interface{}, 0)
values := make([]interface{}, count)
valuePtrs := make([]interface{}, count)
for rows.Next() {
for i := 0; i < count; i++ {
valuePtrs[i] = &values[i]
}
rows.Scan(valuePtrs...)
entry := make(map[string]interface{})
for i, col := range columns {
var v interface{}
val := values[i]
b, ok := val.([]byte)
if ok {
v = string(b)
} else {
v = val
}
entry[col] = v
}
tableData = append(tableData, entry)
}
fmt.Pritln(tableData) //here I am getting data in map
ch <- tableData
}
func dbtest(w http.ResponseWriter, req *http.Request) {
go getdataList(2)
go getdataList(3)
}
func main() {
var err error
db, err = sql.Open("mysql", "root:@/dbName")
if err != nil {
panic(err.Error())
}
defer db.Close()
http.HandleFunc("/dbTest", dbtest)
log.Fatal(http.ListenAndServe(":8080", nil))
}
答案1
得分: 1
你的代码问题在于它在数据从通道中读取之前阻塞了执行流程。当你从getdataList
调用RunQuery
时,RunQuery
试图通过通道ch
发送数据。然而,没有任何地方从ch
中读取数据,因为读取代码位于getdataList
中,并且在调用RunQuery
之后。
因此,RunQuery
永远不会返回,而从ch
读取的goroutine也永远不会触发。为了修复这个问题,你可以尝试将RunQuery
也作为一个goroutine运行:
func getdataList(id int) {
ch := make(chan interface{})
done := make(chan bool)
// 在一个goroutine中运行
go RunQuery(ch, "select id,name, last_name,first_name from persons where id= ?", id)
go func() {
for {
x, ok := <-ch // 这里我没有收到任何通道中的数据
if ok {
fmt.Println(x)
} else {
fmt.Println("done")
done <- true
return
}
}
}()
}
你的代码还有另一个问题。你从未关闭ch
。这可能导致死锁。最理想的关闭位置似乎是在RunQuery
中:
func RunQuery(ch chan interface{}, query string, param interface{}) {
// ...
ch <- tableData
close(ch)
}
英文:
The problem with your code is that it is blocking the execution flow before data can be read from the channel. When you call RunQuery
from getdataList
, RunQuery
tries to send data over channel ch
. However, nothing is reading from ch
because the code to read from it is in getdataList
and it's below the call to RunQuery
.
Therefore, RunQuery
never returns and the goroutine to read from ch
never fires. To fix, You can try running RunQuery
as a goroutine as well:
func getdataList(id int) {
ch := make(chan interface{})
done := make (chan bool)
// run in a goroutine
go RunQuery(ch,"select id,name, last_name,first_name from persons where id= ?", id)
go func() {
for {
x, ok := <-ch //I am not getting any data in channel here
if ok {
fmt.Println(x)
}else {
fmt.Println("done")
done <- true
return
}
}
}()
}
There is another issue in your code. You are never closing ch
. This may result in deadlock. The most ideal place to do this appears to be in RunQuery
:
func RunQuery (ch chan interface{}, query string, param interface{}) {
// ...
ch <- tableData
close(ch)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论