2016-08-24 4 views
0

Ich bin neu zu Golang. Ich versuche, gleichzeitige Abfragen zu mysql db mit Golang zu tun. Ich weiß Kanäle können vom Typ Schnittstelle sein. Wenn ich tableData (type map) in RunQuery Funktion drucke, bekomme ich das Ergebnis. Ich sende tableData zu ch, d. H. Kanal des Typs Schnittstelle. In der Funktion getdataList bekomme ich keinen Wert in ch. Ich verstehe nicht, was ich falsch mache.Kanal des Typs Schnittstelle kein Wert in Golang mit MySql

Im Anschluss ist mein 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)) 

} 

Antwort

0

Das Problem mit Ihrem Code ist, dass es den Ausführungsfluss blockiert, bevor Daten aus dem Kanal gelesen werden. Wenn Sie RunQuery von getdataList aufrufen, versucht RunQuery, Daten über Kanal ch zu senden. Nichts liest jedoch von ch, weil der Code, der daraus zu lesen ist, in getdataList ist und unter dem Aufruf von RunQuery liegt.

Daher RunQuery kehrt nie zurück und die Goroutine zum Lesen von ch wird nie ausgelöst. Um dies zu beheben, können Sie versuchen auch RunQuery als goroutine ausgeführt wird:

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 
      } 

     } 
    }() 
} 

Es gibt ein weiteres Problem in Ihrem Code. Sie schließen nie ch. Dies kann zu einem Deadlock führen. Der ideale Ort, um dies zu tun scheint in RunQuery zu sein:

+0

Dank. Es funktioniert gut. Ich habe jedoch eine Frage, wo sollte ich schließen (ch) in meinem Code. Auch das wird nicht gedruckt. Wird es nur gedruckt, wenn der Kanal geschlossen ist? – Jagrati

+0

Ich habe Zweifel, in 'Fun dbtest', wenn ich' getdataList' nicht mit Go-Routinen verwende. Mit Apache Benchmark bekomme ich eine bessere Leistung, wenn ich nicht die beiden "getdataList" -Funktionen mit Go-Routine verwende. Kannst du mir erklären warum? – Jagrati

+1

kann ich nicht mit Sicherheit sagen, aber meine Vermutung wäre, dass mit goroutines, gleichzeitige Zugriff zwingt SQL '' db', zwei Verbindungen zu öffnen. Ohne goroutines erzeugt der erste Aufruf von 'getdataList' eine Verbindung, die dann beim zweiten Aufruf von' getdataList' verwendet wird. Mein Rat wäre, "getdataList" zu aktualisieren, so dass es eine Liste von IDs benötigt und die meisten Daten mit einer einzigen Abfrage abruft. In diesem Fall würde 'getdataList ([] int {2, 3})' mit einer ähnlich aktualisierten SQL-Abfrage eine noch bessere Leistung bieten. – abhink

Verwandte Themen