MySql 类型接口的通道在 golang 中未接收到值

channel of type interface not receiving value in golang with MySql

我是 golang 的新手。我正在尝试使用 golang 对 mysql db 进行并发查询。我知道通道可以是接口类型。当我在 RunQuery 函数中打印 tableData (type map) 时,我得到了结果。我正在发送 tableDatach,即接口类型的通道。在函数 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)
}