go:将mysql返回数据转换为一个字典数组

  • 2019 年 11 月 22 日
  • 筆記

go官方库返回的是一个rows对象,非常蛋疼。 写了一个很神奇的函数,把返回值db.Rows转换成[]map[string]interface{}结构。

package main    import (      "database/sql"      "fmt"      "github.com/go-sql-driver/mysql"      "log"      "math"      "reflect"      "strconv"      "strings"  )    func main() {      db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/db_viewlib?charset=utf8&parseTime=True")      if err != nil {          log.Fatal(err)      }      defer db.Close()        sql := "select * from t_attr_1400face_common limit 1000"      dbRows, err := db.Query(sql)      if err != nil {          fmt.Printf("query err %v", err)      }        rows := RowsToMap(dbRows)      for _, item := range rows {          fmt.Println(item)      }  }    var BytesKind = reflect.TypeOf(sql.RawBytes{}).Kind()  var TimeKind = reflect.TypeOf(mysql.NullTime{}).Kind()    func checkErr(err error) {      if err != nil {          fmt.Printf("checkErr:%v", err)      }  }    func ToStr(strObj interface{}) string {      switch v := strObj.(type) {      case string:          return v      case []byte:          return string(v)      case nil:          return ""      default:          return fmt.Sprintf("%v", strObj)      }  }    func ToInt(intObj interface{}) int {      // 假定int == int64,运行在64位机      switch v := intObj.(type) {      case []byte:          return ToInt(string(v))      case int:          return v      case int8:          return int(v)      case int16:          return int(v)      case int32:          return int(v)      case int64:          return int(v)      case uint:          return int(v)      case uint8:          return int(v)      case uint16:          return int(v)      case uint32:          return int(v)      case uint64:          if v > math.MaxInt64 {              info := fmt.Sprintf("ToInt, error, overflowd %v", v)              panic(info)          }          return int(v)      case float32:          return int(v)      case float64:          return int(v)      case string:          strv := v          if strings.Contains(v, ".") {              strv = strings.Split(v, ".")[0]          }          if strv == "" {              return 0          }          if intv, err := strconv.Atoi(strv); err == nil {              return intv          }      }      fmt.Printf(fmt.Sprintf("ToInt err, %v, %v not supporttedn", intObj,          reflect.TypeOf(intObj).Kind()))      return 0  }    func RowsToMap(rows *sql.Rows) []map[string]interface{} {      result := make([]map[string]interface{}, 0)        for rows.Next() {          cols, err := rows.Columns()          checkErr(err)            colsTypes, err := rows.ColumnTypes()          checkErr(err)            dest := make([]interface{}, len(cols))          destPointer := make([]interface{}, len(cols))          for i := range dest {              destPointer[i] = &dest[i]          }            err = rows.Scan(destPointer...)          checkErr(err)            rowResult := make(map[string]interface{})          for i, colVal := range dest {              colName := cols[i]              itemType := colsTypes[i].ScanType()              //fmt.Printf("type %v n", itemType)                switch itemType.Kind() {              case BytesKind:                  rowResult[colName] = ToStr(colVal)                case reflect.Int, reflect.Int8,                  reflect.Int16, reflect.Int32, reflect.Int64,                  reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:                    rowResult[colName] = ToInt(colVal)                case TimeKind:                  fmt.Println("time", colVal, reflect.TypeOf(colVal))                  rowResult[colName] = ToStr(colVal)              default:                  rowResult[colName] = ToStr(colVal)              }          }          result = append(result, rowResult)      }      return result  }