Golang中Mysql的results.Scan(&pointerAddress)为何无法填充字段
Golang中Mysql的results.Scan(&pointerAddress)为何无法填充字段 我想使用结构体来填充查询结果,但它抛出了一个错误(sql:在 Scan 中期望 5 个目标参数,但得到 1 个)。我知道我必须手动按正确顺序传递字段。但是否有技巧可以做到这一点?
type ClientUsers struct {
Id int `json:"id"`
FullName string `json:"fullName"`
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
for results.Next() {
var clientUsers ClientUsers
err := results.Scan(&clientUsers )
if err != nil {
fmt.Println("ERROR QUERY IN CLIENT USERS: ", err)
}
usersResponse = append(usersResponse, clientUsers )
}
更多关于Golang中Mysql的results.Scan(&pointerAddress)为何无法填充字段的实战教程也可以访问 https://www.itying.com/category-94-b0.html
嗨,非常感谢您的回答。
更多关于Golang中Mysql的results.Scan(&pointerAddress)为何无法填充字段的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
如果使用内置的 database/sql 包,你将无法实现该功能。Go 语言中存在一些 ORM(对象关系模型),例如 GORM - 旨在对开发者友好的 Golang 优秀 ORM 库。我从未使用过它,但它应该能提供类似你所需的功能。
你有几种选择。你可以仅为了扫描功能而使用ORM。例如,如果你想使用gorm,可以这样做:
type ClientUsers struct {
Id int `json:"id"`
FullName string `json:"fullName"`
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
var clientUsers []ClientUsers
db.Raw("select * from client_users").Scan(&clientUsers)
我通常不喜欢将ORM用于简单查询之外的场景。在我的一个项目中,我使用GORM进行CRUD操作,以减少那些无需动脑的select/insert查询。然后对于所有更复杂/专门的查询,我使用原始SQL。
你也可以看看blockloop/scan,它更专注于扫描功能:
rows, err := db.Query("select * from client_users")
var clientUsers []ClientUsers
err := scan.Rows(&clientUsers, rows)
SQLBoiler也支持绑定:
sqlx也是如此:
最后,你也可以相当容易地使用反射自己实现一些东西:
例如,你可以在其之上使用泛型构建一层抽象。
在Golang中,sql.Rows.Scan()需要接收与查询返回列数相匹配的参数数量。你的代码只传递了一个结构体指针,但查询返回了5列。你需要传递每个字段的指针。
以下是正确的实现方式:
type ClientUsers struct {
Id int `json:"id"`
FullName string `json:"fullName"`
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
for results.Next() {
var clientUsers ClientUsers
// 按查询列的顺序传递每个字段的指针
err := results.Scan(
&clientUsers.Id,
&clientUsers.FullName,
&clientUsers.Username,
&clientUsers.Email,
&clientUsers.Password,
)
if err != nil {
fmt.Println("ERROR QUERY IN CLIENT USERS: ", err)
continue
}
usersResponse = append(usersResponse, clientUsers)
}
如果你不想手动指定每个字段,可以使用反射自动映射,但需要注意性能影响:
import (
"database/sql"
"reflect"
"strings"
)
func scanRowToStruct(rows *sql.Rows, dest interface{}) error {
destValue := reflect.ValueOf(dest).Elem()
destType := destValue.Type()
columns, err := rows.Columns()
if err != nil {
return err
}
values := make([]interface{}, len(columns))
valuePtrs := make([]interface{}, len(columns))
for i := range values {
valuePtrs[i] = &values[i]
}
if err := rows.Scan(valuePtrs...); err != nil {
return err
}
for i, col := range columns {
for j := 0; j < destType.NumField(); j++ {
field := destType.Field(j)
tag := field.Tag.Get("json")
if strings.EqualFold(tag, col) || strings.EqualFold(field.Name, col) {
fieldValue := destValue.Field(j)
if values[i] != nil {
val := reflect.ValueOf(values[i])
if val.Type().ConvertibleTo(fieldValue.Type()) {
fieldValue.Set(val.Convert(fieldValue.Type()))
}
}
break
}
}
}
return nil
}
// 使用方式
for results.Next() {
var clientUsers ClientUsers
err := scanRowToStruct(results, &clientUsers)
if err != nil {
fmt.Println("ERROR: ", err)
continue
}
usersResponse = append(usersResponse, clientUsers)
}
或者使用现有的库如sqlx来简化操作:
import "github.com/jmoiron/sqlx"
// 使用sqlx的StructScan
var clientUsers ClientUsers
err := sqlx.StructScan(results, &clientUsers)
// 或者直接使用sqlx的Select
err := db.Select(&usersResponse, "SELECT * FROM client_users")
使用sqlx是最常见的解决方案,它提供了结构体标签支持:
type ClientUsers struct {
Id int `db:"id" json:"id"`
FullName string `db:"full_name" json:"fullName"`
Username string `db:"username" json:"username"`
Email string `db:"email" json:"email"`
Password string `db:"password" json:"password"`
}

