接口类型的通道没有在Golang中使用MySql接收值

时间:2016-08-24 08:04:25

标签: mysql go goroutine

我是golang的新手。我试图用golang对mysql数据库进行并发查询。我知道频道可以是类型界面。当我在tableData (type map)函数中打印RunQuery时,我得到了结果。我正在向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))

}

1 个答案:

答案 0 :(得分:0)

您的代码存在的问题是,在从通道读取数据之前,它会阻止执行流程。当您从RunQuery致电getdataList时,RunQuery会尝试通过频道ch发送数据。但是,没有任何内容从ch读取,因为从中读取的代码位于getdataList,而且位于RunQuery的调用之下。

因此,RunQuery永远不会返回,并且从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)
}