MySql 类型接口的通道在 golang 中未接收到值
channel of type interface not receiving value in golang with MySql
我是 golang 的新手。我正在尝试使用 golang 对 mysql db 进行并发查询。我知道通道可以是接口类型。当我在 RunQuery
函数中打印 tableData (type map)
时,我得到了结果。我正在发送 tableData
到 ch
,即接口类型的通道。在函数 getdataList
中,我在 ch
中没有得到任何值。我不明白我做错了什么。
以下是我的代码:
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))
}
您的代码的问题是它在从通道读取数据之前阻塞了执行流程。当您从 getdataList
调用 RunQuery
时,RunQuery
尝试通过通道 ch
发送数据。但是,没有从 ch
中读取任何内容,因为要从中读取的代码在 getdataList
中并且在对 RunQuery
.
的调用之下
因此,RunQuery
永远不会 returns 并且从 ch
读取的 goroutine 永远不会触发。要修复,您也可以尝试 运行 RunQuery
作为 goroutine:
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
}
}
}()
}
您的代码中还有另一个问题。您永远不会关闭 ch
。这可能会导致死锁。执行此操作的最理想位置似乎是 RunQuery
:
func RunQuery (ch chan interface{}, query string, param interface{}) {
// ...
ch <- tableData
close(ch)
}
我是 golang 的新手。我正在尝试使用 golang 对 mysql db 进行并发查询。我知道通道可以是接口类型。当我在 RunQuery
函数中打印 tableData (type map)
时,我得到了结果。我正在发送 tableData
到 ch
,即接口类型的通道。在函数 getdataList
中,我在 ch
中没有得到任何值。我不明白我做错了什么。
以下是我的代码:
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))
}
您的代码的问题是它在从通道读取数据之前阻塞了执行流程。当您从 getdataList
调用 RunQuery
时,RunQuery
尝试通过通道 ch
发送数据。但是,没有从 ch
中读取任何内容,因为要从中读取的代码在 getdataList
中并且在对 RunQuery
.
因此,RunQuery
永远不会 returns 并且从 ch
读取的 goroutine 永远不会触发。要修复,您也可以尝试 运行 RunQuery
作为 goroutine:
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
}
}
}()
}
您的代码中还有另一个问题。您永远不会关闭 ch
。这可能会导致死锁。执行此操作的最理想位置似乎是 RunQuery
:
func RunQuery (ch chan interface{}, query string, param interface{}) {
// ...
ch <- tableData
close(ch)
}