php小編小新在這篇文章中將向大家介紹如何從MySQL/Go表獲取行數(shù)據(jù)。MySQL是一種流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),而Go是一種強(qiáng)大的開發(fā)語言。在開發(fā)過程中,我們經(jīng)常需要從數(shù)據(jù)庫中獲取數(shù)據(jù)并進(jìn)行處理。本文將詳細(xì)介紹如何使用Go語言連接MySQL數(shù)據(jù)庫,并通過查詢語句從表中獲取行數(shù)據(jù)。無論您是初學(xué)者還是有經(jīng)驗(yàn)的開發(fā)者,本文都將為您提供有用的指導(dǎo)和示例代碼。讓我們開始吧!
問題內(nèi)容
首先它讀取代碼,以便您了解它的邏輯,當(dāng)運(yùn)行我捕獲它的存儲過程時(shí),它會為我?guī)硪粋€包含我必須返回的數(shù)據(jù)的表,列的名稱確實(shí)會帶來它對我來說,但列的數(shù)據(jù)沒有給我?guī)砣魏螙|西,我無法創(chuàng)建模型,并且存儲過程的響應(yīng)有 n 個列,有 n 個不同的名稱,但列的不同之處在于具有 int 數(shù)據(jù)和字符串?dāng)?shù)據(jù),我需要您從列中捕獲正確的數(shù)據(jù),因?yàn)橐磺姓#兄械臄?shù)據(jù)卻不起作用:
package controllers import ( "database/sql" "encoding/json" "fmt" "net/http" "github.com/gin-gonic/gin" ) type RequestData struct { FromData map[string]interface{} `json:"fromData"` Call string `json:"Call"` } func HandleDatos(c *gin.Context) { var requestData RequestData if err := c.ShouldBindJSON(&requestData); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } fmt.Printf("Ejecutando procedimiento almacenado: CALL %s\n", requestData.Call) fmt.Printf("Parámetros: %v\n", requestData.FromData) var rows *sql.Rows var err error // Verifica si FromData contiene valores if len(requestData.FromData) > 0 { // Si hay valores en FromData, crea una consulta con parámetros query := "CALL " + requestData.Call + "(" params := []interface{}{} for _, value := range requestData.FromData { query += "?, " params = append(params, value) } query = query[:len(query)-2] + ")" rows, err = db.Raw(query, params...).Rows() } else { // Si no hay valores en FromData, ejecuta el procedimiento almacenado sin parámetros rows, err = db.Raw("CALL " + requestData.Call).Rows() } if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } defer rows.Close() // Convierte los resultados en un mapa result := make(map[string]interface{}) columns, err := rows.Columns() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } fmt.Printf("Columnas: %v\n", columns) // Punto de impresión data := [][]interface{}{} // Almacena los datos de filas for rows.Next() { values := make([]interface{}, len(columns)) for i := range columns { values[i] = new(interface{}) } if err := rows.Scan(values...); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } fmt.Printf("Valores escaneados: %v\n", values) // Punto de impresión row := make(map[string]interface{}) for i, col := range columns { val := *(values[i].(*interface{})) row[col] = val } fmt.Printf("Fila escaneada: %v\n", row) // Punto de impresión // Agrega esta fila al resultado data = append(data, values) } fmt.Printf("Datos finales: %v\n", data) // Punto de impresión if len(data) > 0 { result["columns"] = columns result["data"] = data } else { // Si no hay datos, establece un mensaje personalizado result["message"] = "Sin datos" } // Convierte el resultado en JSON y devuelve la respuesta responseJSON, err := json.Marshal(result) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, string(responseJSON)) }
登錄后復(fù)制
這就是它返回給我的內(nèi)容,其中顯示“columns”:[“idPunto”,“nombre”]該部分沒問題,但包含數(shù)據(jù)的行不是我所期望的:
解決方法
將行掃描到接口{}中不會自動將 SQL 類型轉(zhuǎn)換為 Go 類型。相反,使用 ColumnTypes 方法將獲取每列的數(shù)據(jù)類型,允許您動態(tài)分配正確的 Go 類型。 (以下內(nèi)容未經(jīng)測試,僅供參考。)例如
for i := range columns { // Use the column types to determine the appropriate scan type switch columnTypes[i].DatabaseTypeName() { case "INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT": scanArgs[i] = new(int64) default: scanArgs[i] = new(string) } values[i] = scanArgs[i] }
登錄后復(fù)制
在您的腳本中:
package controllers import ( "database/sql" "encoding/json" "fmt" "net/http" "github.com/gin-gonic/gin" ) type RequestData struct { FromData map[string]interface{} `json:"fromData"` Call string `json:"Call"` } func HandleDatos(c *gin.Context) { var requestData RequestData if err := c.ShouldBindJSON(&requestData); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } fmt.Printf("Ejecutando procedimiento almacenado: CALL %s\n", requestData.Call) fmt.Printf("Parámetros: %v\n", requestData.FromData) var rows *sql.Rows var err error // Verifica si FromData contiene valores if len(requestData.FromData) > 0 { // Si hay valores en FromData, crea una consulta con parámetros query := "CALL " + requestData.Call + "(" params := []interface{}{} for _, value := range requestData.FromData { query += "?, " params = append(params, value) } query = query[:len(query)-2] + ")" rows, err = db.Raw(query, params...).Rows() } else { // Si no hay valores en FromData, ejecuta el procedimiento almacenado sin parámetros rows, err = db.Raw("CALL " + requestData.Call).Rows() } if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } defer rows.Close() // Convierte los resultados en un mapa result := make(map[string]interface{}) columns, err := rows.Columns() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } fmt.Printf("Columnas: %v\n", columns) // Punto de impresión data := []map[string]interface{}{} // Almacena los datos de filas // Get the column types columnTypes, err := rows.ColumnTypes() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } for rows.Next() { values := make([]interface{}, len(columns) scanArgs := make([]interface{}, len(columns)) for i := range columns { // Use the column types to determine the appropriate scan type switch columnTypes[i].DatabaseTypeName() { case "INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT": scanArgs[i] = new(int64) default: scanArgs[i] = new(string) } values[i] = scanArgs[i] } if err := rows.Scan(values...); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } fmt.Printf("Valores escaneados: %v\n", values) // Punto de impresión row := make(map[string]interface{}) for i, col := range columns { // Cast the scanned values to the appropriate data types switch columnTypes[i].DatabaseTypeName() { case "INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT": row[col] = *(scanArgs[i].(*int64)) default: row[col] = *(scanArgs[i].(*string)) } } fmt.Printf("Fila escaneada: %v\n", row) // Punto de impresión // Agrega esta fila al resultado data = append(data, row) } fmt.Printf("Datos finales: %v\n", data) // Punto de impresión if len(data) > 0 { result["columns"] = columns result["data"] = data } else { // Si no hay datos, establece un mensaje personalizado result["message"] = "Sin datos" } // Convierte el resultado en JSON y devuelve la respuesta responseJSON, err := json.Marshal(result) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, string(responseJSON)) }
登錄后復(fù)制
nb:您應(yīng)該能夠針對可能遇到的其他數(shù)據(jù)類型擴(kuò)展此邏輯。